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