• 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 	rc = nvmem->reg_read(nvmem->priv, pos, buf, count);
60 
61 	if (rc)
62 		return rc;
63 
64 	return count;
65 }
66 
bin_attr_nvmem_write(struct file * filp,struct kobject * kobj,struct bin_attribute * attr,char * buf,loff_t pos,size_t count)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 
nvmem_sysfs_get_groups(struct nvmem_device * nvmem,const struct nvmem_config * config)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  */
nvmem_sysfs_setup_compat(struct nvmem_device * nvmem,const struct nvmem_config * config)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 
nvmem_sysfs_remove_compat(struct nvmem_device * nvmem,const struct nvmem_config * config)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 }
264