Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.8.
  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		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
258void 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}