Branch data Line data Source code
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 : 0 : 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 : 0 : 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 : 0 : 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 [ # # ]: 0 : 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 [ # # ]: 0 : if (pos >= nvmem->size)
49 : : return 0;
50 : :
51 [ # # ]: 0 : if (count < nvmem->word_size)
52 : : return -EINVAL;
53 : :
54 [ # # ]: 0 : if (pos + count > nvmem->size)
55 : 0 : count = nvmem->size - pos;
56 : :
57 : 0 : count = round_down(count, nvmem->word_size);
58 : :
59 [ # # ]: 0 : if (!nvmem->reg_read)
60 : : return -EPERM;
61 : :
62 : 0 : rc = nvmem->reg_read(nvmem->priv, pos, buf, count);
63 : :
64 [ # # ]: 0 : if (rc)
65 : : return rc;
66 : :
67 : 0 : return count;
68 : : }
69 : :
70 : 0 : 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 [ # # ]: 0 : 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 [ # # ]: 0 : if (pos >= nvmem->size)
86 : : return -EFBIG;
87 : :
88 [ # # ]: 0 : if (count < nvmem->word_size)
89 : : return -EINVAL;
90 : :
91 [ # # ]: 0 : if (pos + count > nvmem->size)
92 : 0 : count = nvmem->size - pos;
93 : :
94 : 0 : count = round_down(count, nvmem->word_size);
95 : :
96 [ # # ]: 0 : if (!nvmem->reg_write)
97 : : return -EPERM;
98 : :
99 : 0 : rc = nvmem->reg_write(nvmem->priv, pos, buf, count);
100 : :
101 [ # # ]: 0 : if (rc)
102 : : return rc;
103 : :
104 : 0 : 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 : 0 : const struct attribute_group **nvmem_sysfs_get_groups(
206 : : struct nvmem_device *nvmem,
207 : : const struct nvmem_config *config)
208 : : {
209 [ # # ]: 0 : if (config->root_only)
210 : 0 : return nvmem->read_only ?
211 [ # # ]: 0 : nvmem_ro_root_dev_groups :
212 : : nvmem_rw_root_dev_groups;
213 : :
214 [ # # ]: 0 : 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 : 0 : int nvmem_sysfs_setup_compat(struct nvmem_device *nvmem,
223 : : const struct nvmem_config *config)
224 : : {
225 : : int rval;
226 : :
227 [ # # ]: 0 : if (!config->compat)
228 : : return 0;
229 : :
230 [ # # ]: 0 : if (!config->base_dev)
231 : : return -EINVAL;
232 : :
233 [ # # ]: 0 : if (nvmem->read_only) {
234 [ # # ]: 0 : if (config->root_only)
235 : 0 : nvmem->eeprom = bin_attr_ro_root_nvmem;
236 : : else
237 : 0 : nvmem->eeprom = bin_attr_ro_nvmem;
238 : : } else {
239 [ # # ]: 0 : if (config->root_only)
240 : 0 : nvmem->eeprom = bin_attr_rw_root_nvmem;
241 : : else
242 : 0 : nvmem->eeprom = bin_attr_rw_nvmem;
243 : : }
244 : 0 : nvmem->eeprom.attr.name = "eeprom";
245 : 0 : nvmem->eeprom.size = nvmem->size;
246 : : #ifdef CONFIG_DEBUG_LOCK_ALLOC
247 : : nvmem->eeprom.attr.key = &eeprom_lock_key;
248 : : #endif
249 : 0 : nvmem->eeprom.private = &nvmem->dev;
250 : 0 : nvmem->base_dev = config->base_dev;
251 : :
252 : 0 : rval = device_create_bin_file(nvmem->base_dev, &nvmem->eeprom);
253 [ # # ]: 0 : if (rval) {
254 : 0 : dev_err(&nvmem->dev,
255 : : "Failed to create eeprom binary file %d\n", rval);
256 : 0 : return rval;
257 : : }
258 : :
259 : 0 : nvmem->flags |= FLAG_COMPAT;
260 : :
261 : 0 : return 0;
262 : : }
263 : :
264 : 0 : void nvmem_sysfs_remove_compat(struct nvmem_device *nvmem,
265 : : const struct nvmem_config *config)
266 : : {
267 [ # # ]: 0 : if (config->compat)
268 : 0 : device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom);
269 : 0 : }
|