Merge tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
[linux-2.6-block.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         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                 if (config->root_only)
229                         nvmem->eeprom = bin_attr_ro_root_nvmem;
230                 else
231                         nvmem->eeprom = bin_attr_ro_nvmem;
232         } else {
233                 if (config->root_only)
234                         nvmem->eeprom = bin_attr_rw_root_nvmem;
235                 else
236                         nvmem->eeprom = bin_attr_rw_nvmem;
237         }
238         nvmem->eeprom.attr.name = "eeprom";
239         nvmem->eeprom.size = nvmem->size;
240 #ifdef CONFIG_DEBUG_LOCK_ALLOC
241         nvmem->eeprom.attr.key = &eeprom_lock_key;
242 #endif
243         nvmem->eeprom.private = &nvmem->dev;
244         nvmem->base_dev = config->base_dev;
245
246         rval = device_create_bin_file(nvmem->base_dev, &nvmem->eeprom);
247         if (rval) {
248                 dev_err(&nvmem->dev,
249                         "Failed to create eeprom binary file %d\n", rval);
250                 return rval;
251         }
252
253         nvmem->flags |= FLAG_COMPAT;
254
255         return 0;
256 }
257
258 void nvmem_sysfs_remove_compat(struct nvmem_device *nvmem,
259                               const struct nvmem_config *config)
260 {
261         if (config->compat)
262                 device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom);
263 }