GNU Linux-libre 5.4.241-gnu1
[releases.git] / drivers / nvmem / nvmem-sysfs.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2019, Linaro Limited
4  */
5 #include "nvmem.h"
6
7 static const char * const nvmem_type_str[] = {
8         [NVMEM_TYPE_UNKNOWN] = "Unknown",
9         [NVMEM_TYPE_EEPROM] = "EEPROM",
10         [NVMEM_TYPE_OTP] = "OTP",
11         [NVMEM_TYPE_BATTERY_BACKED] = "Battery backed",
12 };
13
14 #ifdef CONFIG_DEBUG_LOCK_ALLOC
15 static struct lock_class_key eeprom_lock_key;
16 #endif
17
18 static ssize_t type_show(struct device *dev,
19                          struct device_attribute *attr, char *buf)
20 {
21         struct nvmem_device *nvmem = to_nvmem_device(dev);
22
23         return sprintf(buf, "%s\n", nvmem_type_str[nvmem->type]);
24 }
25
26 static DEVICE_ATTR_RO(type);
27
28 static struct attribute *nvmem_attrs[] = {
29         &dev_attr_type.attr,
30         NULL,
31 };
32
33 static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj,
34                                     struct bin_attribute *attr,
35                                     char *buf, loff_t pos, size_t count)
36 {
37         struct device *dev;
38         struct nvmem_device *nvmem;
39         int rc;
40
41         if (attr->private)
42                 dev = attr->private;
43         else
44                 dev = container_of(kobj, struct device, kobj);
45         nvmem = to_nvmem_device(dev);
46
47         /* Stop the user from reading */
48         if (pos >= nvmem->size)
49                 return 0;
50
51         if (count < nvmem->word_size)
52                 return -EINVAL;
53
54         if (pos + count > nvmem->size)
55                 count = nvmem->size - pos;
56
57         count = round_down(count, nvmem->word_size);
58
59         if (!nvmem->reg_read)
60                 return -EPERM;
61
62         rc = nvmem->reg_read(nvmem->priv, pos, buf, count);
63
64         if (rc)
65                 return rc;
66
67         return count;
68 }
69
70 static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj,
71                                      struct bin_attribute *attr,
72                                      char *buf, loff_t pos, size_t count)
73 {
74         struct device *dev;
75         struct nvmem_device *nvmem;
76         int rc;
77
78         if (attr->private)
79                 dev = attr->private;
80         else
81                 dev = container_of(kobj, struct device, kobj);
82         nvmem = to_nvmem_device(dev);
83
84         /* Stop the user from writing */
85         if (pos >= nvmem->size)
86                 return -EFBIG;
87
88         if (count < nvmem->word_size)
89                 return -EINVAL;
90
91         if (pos + count > nvmem->size)
92                 count = nvmem->size - pos;
93
94         count = round_down(count, nvmem->word_size);
95
96         if (!nvmem->reg_write)
97                 return -EPERM;
98
99         rc = nvmem->reg_write(nvmem->priv, pos, buf, count);
100
101         if (rc)
102                 return rc;
103
104         return count;
105 }
106
107 /* default read/write permissions */
108 static struct bin_attribute bin_attr_rw_nvmem = {
109         .attr   = {
110                 .name   = "nvmem",
111                 .mode   = 0644,
112         },
113         .read   = bin_attr_nvmem_read,
114         .write  = bin_attr_nvmem_write,
115 };
116
117 static struct bin_attribute *nvmem_bin_rw_attributes[] = {
118         &bin_attr_rw_nvmem,
119         NULL,
120 };
121
122 static const struct attribute_group nvmem_bin_rw_group = {
123         .bin_attrs      = nvmem_bin_rw_attributes,
124         .attrs          = nvmem_attrs,
125 };
126
127 static const struct attribute_group *nvmem_rw_dev_groups[] = {
128         &nvmem_bin_rw_group,
129         NULL,
130 };
131
132 /* read only permission */
133 static struct bin_attribute bin_attr_ro_nvmem = {
134         .attr   = {
135                 .name   = "nvmem",
136                 .mode   = 0444,
137         },
138         .read   = bin_attr_nvmem_read,
139 };
140
141 static struct bin_attribute *nvmem_bin_ro_attributes[] = {
142         &bin_attr_ro_nvmem,
143         NULL,
144 };
145
146 static const struct attribute_group nvmem_bin_ro_group = {
147         .bin_attrs      = nvmem_bin_ro_attributes,
148         .attrs          = nvmem_attrs,
149 };
150
151 static const struct attribute_group *nvmem_ro_dev_groups[] = {
152         &nvmem_bin_ro_group,
153         NULL,
154 };
155
156 /* default read/write permissions, root only */
157 static struct bin_attribute bin_attr_rw_root_nvmem = {
158         .attr   = {
159                 .name   = "nvmem",
160                 .mode   = 0600,
161         },
162         .read   = bin_attr_nvmem_read,
163         .write  = bin_attr_nvmem_write,
164 };
165
166 static struct bin_attribute *nvmem_bin_rw_root_attributes[] = {
167         &bin_attr_rw_root_nvmem,
168         NULL,
169 };
170
171 static const struct attribute_group nvmem_bin_rw_root_group = {
172         .bin_attrs      = nvmem_bin_rw_root_attributes,
173         .attrs          = nvmem_attrs,
174 };
175
176 static const struct attribute_group *nvmem_rw_root_dev_groups[] = {
177         &nvmem_bin_rw_root_group,
178         NULL,
179 };
180
181 /* read only permission, root only */
182 static struct bin_attribute bin_attr_ro_root_nvmem = {
183         .attr   = {
184                 .name   = "nvmem",
185                 .mode   = 0400,
186         },
187         .read   = bin_attr_nvmem_read,
188 };
189
190 static struct bin_attribute *nvmem_bin_ro_root_attributes[] = {
191         &bin_attr_ro_root_nvmem,
192         NULL,
193 };
194
195 static const struct attribute_group nvmem_bin_ro_root_group = {
196         .bin_attrs      = nvmem_bin_ro_root_attributes,
197         .attrs          = nvmem_attrs,
198 };
199
200 static const struct attribute_group *nvmem_ro_root_dev_groups[] = {
201         &nvmem_bin_ro_root_group,
202         NULL,
203 };
204
205 const struct attribute_group **nvmem_sysfs_get_groups(
206                                         struct nvmem_device *nvmem,
207                                         const struct nvmem_config *config)
208 {
209         if (config->root_only)
210                 return nvmem->read_only ?
211                         nvmem_ro_root_dev_groups :
212                         nvmem_rw_root_dev_groups;
213
214         return nvmem->read_only ? nvmem_ro_dev_groups : nvmem_rw_dev_groups;
215 }
216
217 /*
218  * nvmem_setup_compat() - Create an additional binary entry in
219  * drivers sys directory, to be backwards compatible with the older
220  * drivers/misc/eeprom drivers.
221  */
222 int nvmem_sysfs_setup_compat(struct nvmem_device *nvmem,
223                               const struct nvmem_config *config)
224 {
225         int rval;
226
227         if (!config->compat)
228                 return 0;
229
230         if (!config->base_dev)
231                 return -EINVAL;
232
233         if (nvmem->read_only) {
234                 if (config->root_only)
235                         nvmem->eeprom = bin_attr_ro_root_nvmem;
236                 else
237                         nvmem->eeprom = bin_attr_ro_nvmem;
238         } else {
239                 if (config->root_only)
240                         nvmem->eeprom = bin_attr_rw_root_nvmem;
241                 else
242                         nvmem->eeprom = bin_attr_rw_nvmem;
243         }
244         nvmem->eeprom.attr.name = "eeprom";
245         nvmem->eeprom.size = nvmem->size;
246 #ifdef CONFIG_DEBUG_LOCK_ALLOC
247         nvmem->eeprom.attr.key = &eeprom_lock_key;
248 #endif
249         nvmem->eeprom.private = &nvmem->dev;
250         nvmem->base_dev = config->base_dev;
251
252         rval = device_create_bin_file(nvmem->base_dev, &nvmem->eeprom);
253         if (rval) {
254                 dev_err(&nvmem->dev,
255                         "Failed to create eeprom binary file %d\n", rval);
256                 return rval;
257         }
258
259         nvmem->flags |= FLAG_COMPAT;
260
261         return 0;
262 }
263
264 void nvmem_sysfs_remove_compat(struct nvmem_device *nvmem,
265                               const struct nvmem_config *config)
266 {
267         if (config->compat)
268                 device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom);
269 }