diff options
-rw-r--r-- | Documentation/ABI/stable/sysfs-bus-nvmem | 2 | ||||
-rw-r--r-- | drivers/nvmem/Kconfig | 10 | ||||
-rw-r--r-- | drivers/nvmem/Makefile | 3 | ||||
-rw-r--r-- | drivers/nvmem/core.c | 264 | ||||
-rw-r--r-- | drivers/nvmem/nvmem-sysfs.c | 256 | ||||
-rw-r--r-- | drivers/nvmem/nvmem.h | 62 |
6 files changed, 337 insertions, 260 deletions
diff --git a/Documentation/ABI/stable/sysfs-bus-nvmem b/Documentation/ABI/stable/sysfs-bus-nvmem index 5923ab4620c5..9ffba8576f7b 100644 --- a/Documentation/ABI/stable/sysfs-bus-nvmem +++ b/Documentation/ABI/stable/sysfs-bus-nvmem | |||
@@ -6,6 +6,8 @@ Description: | |||
6 | This file allows user to read/write the raw NVMEM contents. | 6 | This file allows user to read/write the raw NVMEM contents. |
7 | Permissions for write to this file depends on the nvmem | 7 | Permissions for write to this file depends on the nvmem |
8 | provider configuration. | 8 | provider configuration. |
9 | Note: This file is only present if CONFIG_NVMEM_SYSFS | ||
10 | is enabled | ||
9 | 11 | ||
10 | ex: | 12 | ex: |
11 | hexdump /sys/bus/nvmem/devices/qfprom0/nvmem | 13 | hexdump /sys/bus/nvmem/devices/qfprom0/nvmem |
diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig index a90e9a1ebe55..6b2c4254c2fb 100644 --- a/drivers/nvmem/Kconfig +++ b/drivers/nvmem/Kconfig | |||
@@ -13,6 +13,16 @@ menuconfig NVMEM | |||
13 | 13 | ||
14 | if NVMEM | 14 | if NVMEM |
15 | 15 | ||
16 | config NVMEM_SYSFS | ||
17 | bool "/sys/bus/nvmem/devices/*/nvmem (sysfs interface)" | ||
18 | depends on SYSFS | ||
19 | default y | ||
20 | help | ||
21 | Say Y here to add a sysfs interface for NVMEM. | ||
22 | |||
23 | This interface is mostly used by userspace applications to | ||
24 | read/write directly into nvmem. | ||
25 | |||
16 | config NVMEM_IMX_IIM | 26 | config NVMEM_IMX_IIM |
17 | tristate "i.MX IC Identification Module support" | 27 | tristate "i.MX IC Identification Module support" |
18 | depends on ARCH_MXC || COMPILE_TEST | 28 | depends on ARCH_MXC || COMPILE_TEST |
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile index 4c7ba12a7005..c1fe4768dfef 100644 --- a/drivers/nvmem/Makefile +++ b/drivers/nvmem/Makefile | |||
@@ -6,6 +6,9 @@ | |||
6 | obj-$(CONFIG_NVMEM) += nvmem_core.o | 6 | obj-$(CONFIG_NVMEM) += nvmem_core.o |
7 | nvmem_core-y := core.o | 7 | nvmem_core-y := core.o |
8 | 8 | ||
9 | obj-$(CONFIG_NVMEM_SYSFS) += nvmem_sysfs.o | ||
10 | nvmem_sysfs-y := nvmem-sysfs.o | ||
11 | |||
9 | # Devices | 12 | # Devices |
10 | obj-$(CONFIG_NVMEM_BCM_OCOTP) += nvmem-bcm-ocotp.o | 13 | obj-$(CONFIG_NVMEM_BCM_OCOTP) += nvmem-bcm-ocotp.o |
11 | nvmem-bcm-ocotp-y := bcm-ocotp.o | 14 | nvmem-bcm-ocotp-y := bcm-ocotp.o |
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 5abebf2128b8..c7892c3da91f 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c | |||
@@ -17,27 +17,7 @@ | |||
17 | #include <linux/nvmem-provider.h> | 17 | #include <linux/nvmem-provider.h> |
18 | #include <linux/of.h> | 18 | #include <linux/of.h> |
19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
20 | 20 | #include "nvmem.h" | |
21 | struct nvmem_device { | ||
22 | struct module *owner; | ||
23 | struct device dev; | ||
24 | int stride; | ||
25 | int word_size; | ||
26 | int id; | ||
27 | struct kref refcnt; | ||
28 | size_t size; | ||
29 | bool read_only; | ||
30 | int flags; | ||
31 | enum nvmem_type type; | ||
32 | struct bin_attribute eeprom; | ||
33 | struct device *base_dev; | ||
34 | struct list_head cells; | ||
35 | nvmem_reg_read_t reg_read; | ||
36 | nvmem_reg_write_t reg_write; | ||
37 | void *priv; | ||
38 | }; | ||
39 | |||
40 | #define FLAG_COMPAT BIT(0) | ||
41 | 21 | ||
42 | struct nvmem_cell { | 22 | struct nvmem_cell { |
43 | const char *name; | 23 | const char *name; |
@@ -61,18 +41,7 @@ static LIST_HEAD(nvmem_lookup_list); | |||
61 | 41 | ||
62 | static BLOCKING_NOTIFIER_HEAD(nvmem_notifier); | 42 | static BLOCKING_NOTIFIER_HEAD(nvmem_notifier); |
63 | 43 | ||
64 | static const char * const nvmem_type_str[] = { | ||
65 | [NVMEM_TYPE_UNKNOWN] = "Unknown", | ||
66 | [NVMEM_TYPE_EEPROM] = "EEPROM", | ||
67 | [NVMEM_TYPE_OTP] = "OTP", | ||
68 | [NVMEM_TYPE_BATTERY_BACKED] = "Battery backed", | ||
69 | }; | ||
70 | |||
71 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
72 | static struct lock_class_key eeprom_lock_key; | ||
73 | #endif | ||
74 | 44 | ||
75 | #define to_nvmem_device(d) container_of(d, struct nvmem_device, dev) | ||
76 | static int nvmem_reg_read(struct nvmem_device *nvmem, unsigned int offset, | 45 | static int nvmem_reg_read(struct nvmem_device *nvmem, unsigned int offset, |
77 | void *val, size_t bytes) | 46 | void *val, size_t bytes) |
78 | { | 47 | { |
@@ -91,187 +60,6 @@ static int nvmem_reg_write(struct nvmem_device *nvmem, unsigned int offset, | |||
91 | return -EINVAL; | 60 | return -EINVAL; |
92 | } | 61 | } |
93 | 62 | ||
94 | static ssize_t type_show(struct device *dev, | ||
95 | struct device_attribute *attr, char *buf) | ||
96 | { | ||
97 | struct nvmem_device *nvmem = to_nvmem_device(dev); | ||
98 | |||
99 | return sprintf(buf, "%s\n", nvmem_type_str[nvmem->type]); | ||
100 | } | ||
101 | |||
102 | static DEVICE_ATTR_RO(type); | ||
103 | |||
104 | static struct attribute *nvmem_attrs[] = { | ||
105 | &dev_attr_type.attr, | ||
106 | NULL, | ||
107 | }; | ||
108 | |||
109 | static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj, | ||
110 | struct bin_attribute *attr, | ||
111 | char *buf, loff_t pos, size_t count) | ||
112 | { | ||
113 | struct device *dev; | ||
114 | struct nvmem_device *nvmem; | ||
115 | int rc; | ||
116 | |||
117 | if (attr->private) | ||
118 | dev = attr->private; | ||
119 | else | ||
120 | dev = container_of(kobj, struct device, kobj); | ||
121 | nvmem = to_nvmem_device(dev); | ||
122 | |||
123 | /* Stop the user from reading */ | ||
124 | if (pos >= nvmem->size) | ||
125 | return 0; | ||
126 | |||
127 | if (count < nvmem->word_size) | ||
128 | return -EINVAL; | ||
129 | |||
130 | if (pos + count > nvmem->size) | ||
131 | count = nvmem->size - pos; | ||
132 | |||
133 | count = round_down(count, nvmem->word_size); | ||
134 | |||
135 | rc = nvmem_reg_read(nvmem, pos, buf, count); | ||
136 | |||
137 | if (rc) | ||
138 | return rc; | ||
139 | |||
140 | return count; | ||
141 | } | ||
142 | |||
143 | static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj, | ||
144 | struct bin_attribute *attr, | ||
145 | char *buf, loff_t pos, size_t count) | ||
146 | { | ||
147 | struct device *dev; | ||
148 | struct nvmem_device *nvmem; | ||
149 | int rc; | ||
150 | |||
151 | if (attr->private) | ||
152 | dev = attr->private; | ||
153 | else | ||
154 | dev = container_of(kobj, struct device, kobj); | ||
155 | nvmem = to_nvmem_device(dev); | ||
156 | |||
157 | /* Stop the user from writing */ | ||
158 | if (pos >= nvmem->size) | ||
159 | return -EFBIG; | ||
160 | |||
161 | if (count < nvmem->word_size) | ||
162 | return -EINVAL; | ||
163 | |||
164 | if (pos + count > nvmem->size) | ||
165 | count = nvmem->size - pos; | ||
166 | |||
167 | count = round_down(count, nvmem->word_size); | ||
168 | |||
169 | rc = nvmem_reg_write(nvmem, pos, buf, count); | ||
170 | |||
171 | if (rc) | ||
172 | return rc; | ||
173 | |||
174 | return count; | ||
175 | } | ||
176 | |||
177 | /* default read/write permissions */ | ||
178 | static struct bin_attribute bin_attr_rw_nvmem = { | ||
179 | .attr = { | ||
180 | .name = "nvmem", | ||
181 | .mode = 0644, | ||
182 | }, | ||
183 | .read = bin_attr_nvmem_read, | ||
184 | .write = bin_attr_nvmem_write, | ||
185 | }; | ||
186 | |||
187 | static struct bin_attribute *nvmem_bin_rw_attributes[] = { | ||
188 | &bin_attr_rw_nvmem, | ||
189 | NULL, | ||
190 | }; | ||
191 | |||
192 | static const struct attribute_group nvmem_bin_rw_group = { | ||
193 | .bin_attrs = nvmem_bin_rw_attributes, | ||
194 | .attrs = nvmem_attrs, | ||
195 | }; | ||
196 | |||
197 | static const struct attribute_group *nvmem_rw_dev_groups[] = { | ||
198 | &nvmem_bin_rw_group, | ||
199 | NULL, | ||
200 | }; | ||
201 | |||
202 | /* read only permission */ | ||
203 | static struct bin_attribute bin_attr_ro_nvmem = { | ||
204 | .attr = { | ||
205 | .name = "nvmem", | ||
206 | .mode = 0444, | ||
207 | }, | ||
208 | .read = bin_attr_nvmem_read, | ||
209 | }; | ||
210 | |||
211 | static struct bin_attribute *nvmem_bin_ro_attributes[] = { | ||
212 | &bin_attr_ro_nvmem, | ||
213 | NULL, | ||
214 | }; | ||
215 | |||
216 | static const struct attribute_group nvmem_bin_ro_group = { | ||
217 | .bin_attrs = nvmem_bin_ro_attributes, | ||
218 | .attrs = nvmem_attrs, | ||
219 | }; | ||
220 | |||
221 | static const struct attribute_group *nvmem_ro_dev_groups[] = { | ||
222 | &nvmem_bin_ro_group, | ||
223 | NULL, | ||
224 | }; | ||
225 | |||
226 | /* default read/write permissions, root only */ | ||
227 | static struct bin_attribute bin_attr_rw_root_nvmem = { | ||
228 | .attr = { | ||
229 | .name = "nvmem", | ||
230 | .mode = 0600, | ||
231 | }, | ||
232 | .read = bin_attr_nvmem_read, | ||
233 | .write = bin_attr_nvmem_write, | ||
234 | }; | ||
235 | |||
236 | static struct bin_attribute *nvmem_bin_rw_root_attributes[] = { | ||
237 | &bin_attr_rw_root_nvmem, | ||
238 | NULL, | ||
239 | }; | ||
240 | |||
241 | static const struct attribute_group nvmem_bin_rw_root_group = { | ||
242 | .bin_attrs = nvmem_bin_rw_root_attributes, | ||
243 | .attrs = nvmem_attrs, | ||
244 | }; | ||
245 | |||
246 | static const struct attribute_group *nvmem_rw_root_dev_groups[] = { | ||
247 | &nvmem_bin_rw_root_group, | ||
248 | NULL, | ||
249 | }; | ||
250 | |||
251 | /* read only permission, root only */ | ||
252 | static struct bin_attribute bin_attr_ro_root_nvmem = { | ||
253 | .attr = { | ||
254 | .name = "nvmem", | ||
255 | .mode = 0400, | ||
256 | }, | ||
257 | .read = bin_attr_nvmem_read, | ||
258 | }; | ||
259 | |||
260 | static struct bin_attribute *nvmem_bin_ro_root_attributes[] = { | ||
261 | &bin_attr_ro_root_nvmem, | ||
262 | NULL, | ||
263 | }; | ||
264 | |||
265 | static const struct attribute_group nvmem_bin_ro_root_group = { | ||
266 | .bin_attrs = nvmem_bin_ro_root_attributes, | ||
267 | .attrs = nvmem_attrs, | ||
268 | }; | ||
269 | |||
270 | static const struct attribute_group *nvmem_ro_root_dev_groups[] = { | ||
271 | &nvmem_bin_ro_root_group, | ||
272 | NULL, | ||
273 | }; | ||
274 | |||
275 | static void nvmem_release(struct device *dev) | 63 | static void nvmem_release(struct device *dev) |
276 | { | 64 | { |
277 | struct nvmem_device *nvmem = to_nvmem_device(dev); | 65 | struct nvmem_device *nvmem = to_nvmem_device(dev); |
@@ -422,43 +210,6 @@ err: | |||
422 | return rval; | 210 | return rval; |
423 | } | 211 | } |
424 | 212 | ||
425 | /* | ||
426 | * nvmem_setup_compat() - Create an additional binary entry in | ||
427 | * drivers sys directory, to be backwards compatible with the older | ||
428 | * drivers/misc/eeprom drivers. | ||
429 | */ | ||
430 | static int nvmem_setup_compat(struct nvmem_device *nvmem, | ||
431 | const struct nvmem_config *config) | ||
432 | { | ||
433 | int rval; | ||
434 | |||
435 | if (!config->base_dev) | ||
436 | return -EINVAL; | ||
437 | |||
438 | if (nvmem->read_only) | ||
439 | nvmem->eeprom = bin_attr_ro_root_nvmem; | ||
440 | else | ||
441 | nvmem->eeprom = bin_attr_rw_root_nvmem; | ||
442 | nvmem->eeprom.attr.name = "eeprom"; | ||
443 | nvmem->eeprom.size = nvmem->size; | ||
444 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
445 | nvmem->eeprom.attr.key = &eeprom_lock_key; | ||
446 | #endif | ||
447 | nvmem->eeprom.private = &nvmem->dev; | ||
448 | nvmem->base_dev = config->base_dev; | ||
449 | |||
450 | rval = device_create_bin_file(nvmem->base_dev, &nvmem->eeprom); | ||
451 | if (rval) { | ||
452 | dev_err(&nvmem->dev, | ||
453 | "Failed to create eeprom binary file %d\n", rval); | ||
454 | return rval; | ||
455 | } | ||
456 | |||
457 | nvmem->flags |= FLAG_COMPAT; | ||
458 | |||
459 | return 0; | ||
460 | } | ||
461 | |||
462 | /** | 213 | /** |
463 | * nvmem_register_notifier() - Register a notifier block for nvmem events. | 214 | * nvmem_register_notifier() - Register a notifier block for nvmem events. |
464 | * | 215 | * |
@@ -651,14 +402,7 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) | |||
651 | nvmem->read_only = device_property_present(config->dev, "read-only") || | 402 | nvmem->read_only = device_property_present(config->dev, "read-only") || |
652 | config->read_only || !nvmem->reg_write; | 403 | config->read_only || !nvmem->reg_write; |
653 | 404 | ||
654 | if (config->root_only) | 405 | nvmem->dev.groups = nvmem_sysfs_get_groups(nvmem, config); |
655 | nvmem->dev.groups = nvmem->read_only ? | ||
656 | nvmem_ro_root_dev_groups : | ||
657 | nvmem_rw_root_dev_groups; | ||
658 | else | ||
659 | nvmem->dev.groups = nvmem->read_only ? | ||
660 | nvmem_ro_dev_groups : | ||
661 | nvmem_rw_dev_groups; | ||
662 | 406 | ||
663 | device_initialize(&nvmem->dev); | 407 | device_initialize(&nvmem->dev); |
664 | 408 | ||
@@ -669,7 +413,7 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) | |||
669 | goto err_put_device; | 413 | goto err_put_device; |
670 | 414 | ||
671 | if (config->compat) { | 415 | if (config->compat) { |
672 | rval = nvmem_setup_compat(nvmem, config); | 416 | rval = nvmem_sysfs_setup_compat(nvmem, config); |
673 | if (rval) | 417 | if (rval) |
674 | goto err_device_del; | 418 | goto err_device_del; |
675 | } | 419 | } |
@@ -696,7 +440,7 @@ err_remove_cells: | |||
696 | nvmem_device_remove_all_cells(nvmem); | 440 | nvmem_device_remove_all_cells(nvmem); |
697 | err_teardown_compat: | 441 | err_teardown_compat: |
698 | if (config->compat) | 442 | if (config->compat) |
699 | device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); | 443 | nvmem_sysfs_remove_compat(nvmem, config); |
700 | err_device_del: | 444 | err_device_del: |
701 | device_del(&nvmem->dev); | 445 | device_del(&nvmem->dev); |
702 | err_put_device: | 446 | err_put_device: |
diff --git a/drivers/nvmem/nvmem-sysfs.c b/drivers/nvmem/nvmem-sysfs.c new file mode 100644 index 000000000000..6f303b91f6e7 --- /dev/null +++ b/drivers/nvmem/nvmem-sysfs.c | |||
@@ -0,0 +1,256 @@ | |||
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 | rc = nvmem->reg_read(nvmem->priv, pos, buf, count); | ||
60 | |||
61 | if (rc) | ||
62 | return rc; | ||
63 | |||
64 | return count; | ||
65 | } | ||
66 | |||
67 | static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj, | ||
68 | struct bin_attribute *attr, | ||
69 | char *buf, loff_t pos, size_t count) | ||
70 | { | ||
71 | struct device *dev; | ||
72 | struct nvmem_device *nvmem; | ||
73 | int rc; | ||
74 | |||
75 | if (attr->private) | ||
76 | dev = attr->private; | ||
77 | else | ||
78 | dev = container_of(kobj, struct device, kobj); | ||
79 | nvmem = to_nvmem_device(dev); | ||
80 | |||
81 | /* Stop the user from writing */ | ||
82 | if (pos >= nvmem->size) | ||
83 | return -EFBIG; | ||
84 | |||
85 | if (count < nvmem->word_size) | ||
86 | return -EINVAL; | ||
87 | |||
88 | if (pos + count > nvmem->size) | ||
89 | count = nvmem->size - pos; | ||
90 | |||
91 | count = round_down(count, nvmem->word_size); | ||
92 | |||
93 | rc = nvmem->reg_write(nvmem->priv, pos, buf, count); | ||
94 | |||
95 | if (rc) | ||
96 | return rc; | ||
97 | |||
98 | return count; | ||
99 | } | ||
100 | |||
101 | /* default read/write permissions */ | ||
102 | static struct bin_attribute bin_attr_rw_nvmem = { | ||
103 | .attr = { | ||
104 | .name = "nvmem", | ||
105 | .mode = 0644, | ||
106 | }, | ||
107 | .read = bin_attr_nvmem_read, | ||
108 | .write = bin_attr_nvmem_write, | ||
109 | }; | ||
110 | |||
111 | static struct bin_attribute *nvmem_bin_rw_attributes[] = { | ||
112 | &bin_attr_rw_nvmem, | ||
113 | NULL, | ||
114 | }; | ||
115 | |||
116 | static const struct attribute_group nvmem_bin_rw_group = { | ||
117 | .bin_attrs = nvmem_bin_rw_attributes, | ||
118 | .attrs = nvmem_attrs, | ||
119 | }; | ||
120 | |||
121 | static const struct attribute_group *nvmem_rw_dev_groups[] = { | ||
122 | &nvmem_bin_rw_group, | ||
123 | NULL, | ||
124 | }; | ||
125 | |||
126 | /* read only permission */ | ||
127 | static struct bin_attribute bin_attr_ro_nvmem = { | ||
128 | .attr = { | ||
129 | .name = "nvmem", | ||
130 | .mode = 0444, | ||
131 | }, | ||
132 | .read = bin_attr_nvmem_read, | ||
133 | }; | ||
134 | |||
135 | static struct bin_attribute *nvmem_bin_ro_attributes[] = { | ||
136 | &bin_attr_ro_nvmem, | ||
137 | NULL, | ||
138 | }; | ||
139 | |||
140 | static const struct attribute_group nvmem_bin_ro_group = { | ||
141 | .bin_attrs = nvmem_bin_ro_attributes, | ||
142 | .attrs = nvmem_attrs, | ||
143 | }; | ||
144 | |||
145 | static const struct attribute_group *nvmem_ro_dev_groups[] = { | ||
146 | &nvmem_bin_ro_group, | ||
147 | NULL, | ||
148 | }; | ||
149 | |||
150 | /* default read/write permissions, root only */ | ||
151 | static struct bin_attribute bin_attr_rw_root_nvmem = { | ||
152 | .attr = { | ||
153 | .name = "nvmem", | ||
154 | .mode = 0600, | ||
155 | }, | ||
156 | .read = bin_attr_nvmem_read, | ||
157 | .write = bin_attr_nvmem_write, | ||
158 | }; | ||
159 | |||
160 | static struct bin_attribute *nvmem_bin_rw_root_attributes[] = { | ||
161 | &bin_attr_rw_root_nvmem, | ||
162 | NULL, | ||
163 | }; | ||
164 | |||
165 | static const struct attribute_group nvmem_bin_rw_root_group = { | ||
166 | .bin_attrs = nvmem_bin_rw_root_attributes, | ||
167 | .attrs = nvmem_attrs, | ||
168 | }; | ||
169 | |||
170 | static const struct attribute_group *nvmem_rw_root_dev_groups[] = { | ||
171 | &nvmem_bin_rw_root_group, | ||
172 | NULL, | ||
173 | }; | ||
174 | |||
175 | /* read only permission, root only */ | ||
176 | static struct bin_attribute bin_attr_ro_root_nvmem = { | ||
177 | .attr = { | ||
178 | .name = "nvmem", | ||
179 | .mode = 0400, | ||
180 | }, | ||
181 | .read = bin_attr_nvmem_read, | ||
182 | }; | ||
183 | |||
184 | static struct bin_attribute *nvmem_bin_ro_root_attributes[] = { | ||
185 | &bin_attr_ro_root_nvmem, | ||
186 | NULL, | ||
187 | }; | ||
188 | |||
189 | static const struct attribute_group nvmem_bin_ro_root_group = { | ||
190 | .bin_attrs = nvmem_bin_ro_root_attributes, | ||
191 | .attrs = nvmem_attrs, | ||
192 | }; | ||
193 | |||
194 | static const struct attribute_group *nvmem_ro_root_dev_groups[] = { | ||
195 | &nvmem_bin_ro_root_group, | ||
196 | NULL, | ||
197 | }; | ||
198 | |||
199 | const struct attribute_group **nvmem_sysfs_get_groups( | ||
200 | struct nvmem_device *nvmem, | ||
201 | const struct nvmem_config *config) | ||
202 | { | ||
203 | if (config->root_only) | ||
204 | return nvmem->read_only ? | ||
205 | nvmem_ro_root_dev_groups : | ||
206 | nvmem_rw_root_dev_groups; | ||
207 | |||
208 | return nvmem->read_only ? nvmem_ro_dev_groups : nvmem_rw_dev_groups; | ||
209 | } | ||
210 | |||
211 | /* | ||
212 | * nvmem_setup_compat() - Create an additional binary entry in | ||
213 | * drivers sys directory, to be backwards compatible with the older | ||
214 | * drivers/misc/eeprom drivers. | ||
215 | */ | ||
216 | int nvmem_sysfs_setup_compat(struct nvmem_device *nvmem, | ||
217 | const struct nvmem_config *config) | ||
218 | { | ||
219 | int rval; | ||
220 | |||
221 | if (!config->compat) | ||
222 | return 0; | ||
223 | |||
224 | if (!config->base_dev) | ||
225 | return -EINVAL; | ||
226 | |||
227 | if (nvmem->read_only) | ||
228 | nvmem->eeprom = bin_attr_ro_root_nvmem; | ||
229 | else | ||
230 | nvmem->eeprom = bin_attr_rw_root_nvmem; | ||
231 | nvmem->eeprom.attr.name = "eeprom"; | ||
232 | nvmem->eeprom.size = nvmem->size; | ||
233 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
234 | nvmem->eeprom.attr.key = &eeprom_lock_key; | ||
235 | #endif | ||
236 | nvmem->eeprom.private = &nvmem->dev; | ||
237 | nvmem->base_dev = config->base_dev; | ||
238 | |||
239 | rval = device_create_bin_file(nvmem->base_dev, &nvmem->eeprom); | ||
240 | if (rval) { | ||
241 | dev_err(&nvmem->dev, | ||
242 | "Failed to create eeprom binary file %d\n", rval); | ||
243 | return rval; | ||
244 | } | ||
245 | |||
246 | nvmem->flags |= FLAG_COMPAT; | ||
247 | |||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | void nvmem_sysfs_remove_compat(struct nvmem_device *nvmem, | ||
252 | const struct nvmem_config *config) | ||
253 | { | ||
254 | if (config->compat) | ||
255 | device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); | ||
256 | } | ||
diff --git a/drivers/nvmem/nvmem.h b/drivers/nvmem/nvmem.h new file mode 100644 index 000000000000..eb8ed7121fa3 --- /dev/null +++ b/drivers/nvmem/nvmem.h | |||
@@ -0,0 +1,62 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | |||
3 | #ifndef _DRIVERS_NVMEM_H | ||
4 | #define _DRIVERS_NVMEM_H | ||
5 | |||
6 | #include <linux/device.h> | ||
7 | #include <linux/fs.h> | ||
8 | #include <linux/kref.h> | ||
9 | #include <linux/list.h> | ||
10 | #include <linux/nvmem-consumer.h> | ||
11 | #include <linux/nvmem-provider.h> | ||
12 | |||
13 | struct nvmem_device { | ||
14 | struct module *owner; | ||
15 | struct device dev; | ||
16 | int stride; | ||
17 | int word_size; | ||
18 | int id; | ||
19 | struct kref refcnt; | ||
20 | size_t size; | ||
21 | bool read_only; | ||
22 | int flags; | ||
23 | enum nvmem_type type; | ||
24 | struct bin_attribute eeprom; | ||
25 | struct device *base_dev; | ||
26 | struct list_head cells; | ||
27 | nvmem_reg_read_t reg_read; | ||
28 | nvmem_reg_write_t reg_write; | ||
29 | void *priv; | ||
30 | }; | ||
31 | |||
32 | #define to_nvmem_device(d) container_of(d, struct nvmem_device, dev) | ||
33 | #define FLAG_COMPAT BIT(0) | ||
34 | |||
35 | #ifdef CONFIG_NVMEM_SYSFS | ||
36 | const struct attribute_group **nvmem_sysfs_get_groups( | ||
37 | struct nvmem_device *nvmem, | ||
38 | const struct nvmem_config *config); | ||
39 | int nvmem_sysfs_setup_compat(struct nvmem_device *nvmem, | ||
40 | const struct nvmem_config *config); | ||
41 | void nvmem_sysfs_remove_compat(struct nvmem_device *nvmem, | ||
42 | const struct nvmem_config *config); | ||
43 | #else | ||
44 | static inline const struct attribute_group **nvmem_sysfs_get_groups( | ||
45 | struct nvmem_device *nvmem, | ||
46 | const struct nvmem_config *config) | ||
47 | { | ||
48 | return NULL; | ||
49 | } | ||
50 | |||
51 | static inline int nvmem_sysfs_setup_compat(struct nvmem_device *nvmem, | ||
52 | const struct nvmem_config *config) | ||
53 | { | ||
54 | return -ENOSYS; | ||
55 | } | ||
56 | static inline void nvmem_sysfs_remove_compat(struct nvmem_device *nvmem, | ||
57 | const struct nvmem_config *config) | ||
58 | { | ||
59 | } | ||
60 | #endif /* CONFIG_NVMEM_SYSFS */ | ||
61 | |||
62 | #endif /* _DRIVERS_NVMEM_H */ | ||