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 : 0 : 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 : 0 : struct device *dev;
38 : 0 : struct nvmem_device *nvmem;
39 : 0 : int rc;
40 : :
41 [ # # ]: 0 : if (attr->private)
42 : 0 : dev = attr->private;
43 : : else
44 : : dev = container_of(kobj, struct device, kobj);
45 : 0 : 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 : rc = nvmem->reg_read(nvmem->priv, pos, buf, count);
60 : :
61 [ # # ]: 0 : if (rc)
62 : 0 : return rc;
63 : :
64 : 0 : return count;
65 : : }
66 : :
67 : 0 : 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 : 0 : struct device *dev;
72 : 0 : struct nvmem_device *nvmem;
73 : 0 : int rc;
74 : :
75 [ # # ]: 0 : if (attr->private)
76 : 0 : dev = attr->private;
77 : : else
78 : : dev = container_of(kobj, struct device, kobj);
79 : 0 : nvmem = to_nvmem_device(dev);
80 : :
81 : : /* Stop the user from writing */
82 [ # # ]: 0 : if (pos >= nvmem->size)
83 : : return -EFBIG;
84 : :
85 [ # # ]: 0 : if (count < nvmem->word_size)
86 : : return -EINVAL;
87 : :
88 [ # # ]: 0 : if (pos + count > nvmem->size)
89 : 0 : count = nvmem->size - pos;
90 : :
91 : 0 : count = round_down(count, nvmem->word_size);
92 : :
93 : 0 : rc = nvmem->reg_write(nvmem->priv, pos, buf, count);
94 : :
95 [ # # ]: 0 : if (rc)
96 : 0 : return rc;
97 : :
98 : 0 : 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 : 78 : const struct attribute_group **nvmem_sysfs_get_groups(
200 : : struct nvmem_device *nvmem,
201 : : const struct nvmem_config *config)
202 : : {
203 [ - + ]: 78 : if (config->root_only)
204 : 0 : return nvmem->read_only ?
205 [ # # ]: 0 : nvmem_ro_root_dev_groups :
206 : : nvmem_rw_root_dev_groups;
207 : :
208 [ + - ]: 78 : 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 : 0 : int nvmem_sysfs_setup_compat(struct nvmem_device *nvmem,
217 : : const struct nvmem_config *config)
218 : : {
219 : 0 : int rval;
220 : :
221 [ # # ]: 0 : if (!config->compat)
222 : : return 0;
223 : :
224 [ # # ]: 0 : if (!config->base_dev)
225 : : return -EINVAL;
226 : :
227 [ # # ]: 0 : if (nvmem->read_only) {
228 [ # # ]: 0 : if (config->root_only)
229 : 0 : nvmem->eeprom = bin_attr_ro_root_nvmem;
230 : : else
231 : 0 : nvmem->eeprom = bin_attr_ro_nvmem;
232 : : } else {
233 [ # # ]: 0 : if (config->root_only)
234 : 0 : nvmem->eeprom = bin_attr_rw_root_nvmem;
235 : : else
236 : 0 : nvmem->eeprom = bin_attr_rw_nvmem;
237 : : }
238 : 0 : nvmem->eeprom.attr.name = "eeprom";
239 : 0 : nvmem->eeprom.size = nvmem->size;
240 : : #ifdef CONFIG_DEBUG_LOCK_ALLOC
241 : : nvmem->eeprom.attr.key = &eeprom_lock_key;
242 : : #endif
243 : 0 : nvmem->eeprom.private = &nvmem->dev;
244 : 0 : nvmem->base_dev = config->base_dev;
245 : :
246 : 0 : rval = device_create_bin_file(nvmem->base_dev, &nvmem->eeprom);
247 [ # # ]: 0 : if (rval) {
248 : 0 : dev_err(&nvmem->dev,
249 : : "Failed to create eeprom binary file %d\n", rval);
250 : 0 : return rval;
251 : : }
252 : :
253 : 0 : nvmem->flags |= FLAG_COMPAT;
254 : :
255 : 0 : return 0;
256 : : }
257 : :
258 : 0 : void nvmem_sysfs_remove_compat(struct nvmem_device *nvmem,
259 : : const struct nvmem_config *config)
260 : : {
261 [ # # ]: 0 : if (config->compat)
262 : 0 : device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom);
263 : 0 : }
|