]> git.ipfire.org Git - thirdparty/kernel/stable.git/blame - drivers/nvmem/nvmem-sysfs.c
NFS4: Only set creation opendata if O_CREAT
[thirdparty/kernel/stable.git] / drivers / nvmem / nvmem-sysfs.c
CommitLineData
ae0c2d72
SK
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2019, Linaro Limited
4 */
5#include "nvmem.h"
6
7static 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
15static struct lock_class_key eeprom_lock_key;
16#endif
17
18static 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
26static DEVICE_ATTR_RO(type);
27
28static struct attribute *nvmem_attrs[] = {
29 &dev_attr_type.attr,
30 NULL,
31};
32
33static 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
67static 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 */
102static 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
111static struct bin_attribute *nvmem_bin_rw_attributes[] = {
112 &bin_attr_rw_nvmem,
113 NULL,
114};
115
116static const struct attribute_group nvmem_bin_rw_group = {
117 .bin_attrs = nvmem_bin_rw_attributes,
118 .attrs = nvmem_attrs,
119};
120
121static const struct attribute_group *nvmem_rw_dev_groups[] = {
122 &nvmem_bin_rw_group,
123 NULL,
124};
125
126/* read only permission */
127static struct bin_attribute bin_attr_ro_nvmem = {
128 .attr = {
129 .name = "nvmem",
130 .mode = 0444,
131 },
132 .read = bin_attr_nvmem_read,
133};
134
135static struct bin_attribute *nvmem_bin_ro_attributes[] = {
136 &bin_attr_ro_nvmem,
137 NULL,
138};
139
140static const struct attribute_group nvmem_bin_ro_group = {
141 .bin_attrs = nvmem_bin_ro_attributes,
142 .attrs = nvmem_attrs,
143};
144
145static const struct attribute_group *nvmem_ro_dev_groups[] = {
146 &nvmem_bin_ro_group,
147 NULL,
148};
149
150/* default read/write permissions, root only */
151static 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
160static struct bin_attribute *nvmem_bin_rw_root_attributes[] = {
161 &bin_attr_rw_root_nvmem,
162 NULL,
163};
164
165static const struct attribute_group nvmem_bin_rw_root_group = {
166 .bin_attrs = nvmem_bin_rw_root_attributes,
167 .attrs = nvmem_attrs,
168};
169
170static 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 */
176static 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
184static struct bin_attribute *nvmem_bin_ro_root_attributes[] = {
185 &bin_attr_ro_root_nvmem,
186 NULL,
187};
188
189static const struct attribute_group nvmem_bin_ro_root_group = {
190 .bin_attrs = nvmem_bin_ro_root_attributes,
191 .attrs = nvmem_attrs,
192};
193
194static const struct attribute_group *nvmem_ro_root_dev_groups[] = {
195 &nvmem_bin_ro_root_group,
196 NULL,
197};
198
199const 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 */
216int 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
251void 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}