xref: /linux/drivers/nvmem/core.c (revision 165589f0cb52b34db12e15676a034b8f83dfa756)
1b1c1db98SBartosz Golaszewski // SPDX-License-Identifier: GPL-2.0
2eace75cfSSrinivas Kandagatla /*
3eace75cfSSrinivas Kandagatla  * nvmem framework core.
4eace75cfSSrinivas Kandagatla  *
5eace75cfSSrinivas Kandagatla  * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
6eace75cfSSrinivas Kandagatla  * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
7eace75cfSSrinivas Kandagatla  */
8eace75cfSSrinivas Kandagatla 
9eace75cfSSrinivas Kandagatla #include <linux/device.h>
10eace75cfSSrinivas Kandagatla #include <linux/export.h>
11eace75cfSSrinivas Kandagatla #include <linux/fs.h>
12eace75cfSSrinivas Kandagatla #include <linux/idr.h>
13eace75cfSSrinivas Kandagatla #include <linux/init.h>
14c1de7f43SBartosz Golaszewski #include <linux/kref.h>
15eace75cfSSrinivas Kandagatla #include <linux/module.h>
16eace75cfSSrinivas Kandagatla #include <linux/nvmem-consumer.h>
17eace75cfSSrinivas Kandagatla #include <linux/nvmem-provider.h>
18eace75cfSSrinivas Kandagatla #include <linux/of.h>
19eace75cfSSrinivas Kandagatla #include <linux/slab.h>
20eace75cfSSrinivas Kandagatla 
21eace75cfSSrinivas Kandagatla struct nvmem_device {
22eace75cfSSrinivas Kandagatla 	struct module		*owner;
23eace75cfSSrinivas Kandagatla 	struct device		dev;
24eace75cfSSrinivas Kandagatla 	int			stride;
25eace75cfSSrinivas Kandagatla 	int			word_size;
26eace75cfSSrinivas Kandagatla 	int			id;
27c1de7f43SBartosz Golaszewski 	struct kref		refcnt;
28eace75cfSSrinivas Kandagatla 	size_t			size;
29eace75cfSSrinivas Kandagatla 	bool			read_only;
30b6c217abSAndrew Lunn 	int			flags;
31b6c217abSAndrew Lunn 	struct bin_attribute	eeprom;
32b6c217abSAndrew Lunn 	struct device		*base_dev;
33c7235ee3SBartosz Golaszewski 	struct list_head	cells;
34795ddd18SSrinivas Kandagatla 	nvmem_reg_read_t	reg_read;
35795ddd18SSrinivas Kandagatla 	nvmem_reg_write_t	reg_write;
36795ddd18SSrinivas Kandagatla 	void *priv;
37eace75cfSSrinivas Kandagatla };
38eace75cfSSrinivas Kandagatla 
39b6c217abSAndrew Lunn #define FLAG_COMPAT		BIT(0)
40b6c217abSAndrew Lunn 
41eace75cfSSrinivas Kandagatla struct nvmem_cell {
42eace75cfSSrinivas Kandagatla 	const char		*name;
43eace75cfSSrinivas Kandagatla 	int			offset;
44eace75cfSSrinivas Kandagatla 	int			bytes;
45eace75cfSSrinivas Kandagatla 	int			bit_offset;
46eace75cfSSrinivas Kandagatla 	int			nbits;
47eace75cfSSrinivas Kandagatla 	struct nvmem_device	*nvmem;
48eace75cfSSrinivas Kandagatla 	struct list_head	node;
49eace75cfSSrinivas Kandagatla };
50eace75cfSSrinivas Kandagatla 
51eace75cfSSrinivas Kandagatla static DEFINE_MUTEX(nvmem_mutex);
52eace75cfSSrinivas Kandagatla static DEFINE_IDA(nvmem_ida);
53eace75cfSSrinivas Kandagatla 
54b985f4cbSBartosz Golaszewski static DEFINE_MUTEX(nvmem_cell_mutex);
55b985f4cbSBartosz Golaszewski static LIST_HEAD(nvmem_cell_tables);
56b985f4cbSBartosz Golaszewski 
57506157beSBartosz Golaszewski static DEFINE_MUTEX(nvmem_lookup_mutex);
58506157beSBartosz Golaszewski static LIST_HEAD(nvmem_lookup_list);
59506157beSBartosz Golaszewski 
60bee1138bSBartosz Golaszewski static BLOCKING_NOTIFIER_HEAD(nvmem_notifier);
61bee1138bSBartosz Golaszewski 
62b6c217abSAndrew Lunn #ifdef CONFIG_DEBUG_LOCK_ALLOC
63b6c217abSAndrew Lunn static struct lock_class_key eeprom_lock_key;
64b6c217abSAndrew Lunn #endif
65b6c217abSAndrew Lunn 
66eace75cfSSrinivas Kandagatla #define to_nvmem_device(d) container_of(d, struct nvmem_device, dev)
67795ddd18SSrinivas Kandagatla static int nvmem_reg_read(struct nvmem_device *nvmem, unsigned int offset,
68795ddd18SSrinivas Kandagatla 			  void *val, size_t bytes)
69795ddd18SSrinivas Kandagatla {
70795ddd18SSrinivas Kandagatla 	if (nvmem->reg_read)
71795ddd18SSrinivas Kandagatla 		return nvmem->reg_read(nvmem->priv, offset, val, bytes);
72795ddd18SSrinivas Kandagatla 
73795ddd18SSrinivas Kandagatla 	return -EINVAL;
74795ddd18SSrinivas Kandagatla }
75795ddd18SSrinivas Kandagatla 
76795ddd18SSrinivas Kandagatla static int nvmem_reg_write(struct nvmem_device *nvmem, unsigned int offset,
77795ddd18SSrinivas Kandagatla 			   void *val, size_t bytes)
78795ddd18SSrinivas Kandagatla {
79795ddd18SSrinivas Kandagatla 	if (nvmem->reg_write)
80795ddd18SSrinivas Kandagatla 		return nvmem->reg_write(nvmem->priv, offset, val, bytes);
81795ddd18SSrinivas Kandagatla 
82795ddd18SSrinivas Kandagatla 	return -EINVAL;
83795ddd18SSrinivas Kandagatla }
84eace75cfSSrinivas Kandagatla 
85eace75cfSSrinivas Kandagatla static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj,
86eace75cfSSrinivas Kandagatla 				    struct bin_attribute *attr,
87eace75cfSSrinivas Kandagatla 				    char *buf, loff_t pos, size_t count)
88eace75cfSSrinivas Kandagatla {
89b6c217abSAndrew Lunn 	struct device *dev;
90b6c217abSAndrew Lunn 	struct nvmem_device *nvmem;
91eace75cfSSrinivas Kandagatla 	int rc;
92eace75cfSSrinivas Kandagatla 
93b6c217abSAndrew Lunn 	if (attr->private)
94b6c217abSAndrew Lunn 		dev = attr->private;
95b6c217abSAndrew Lunn 	else
96b6c217abSAndrew Lunn 		dev = container_of(kobj, struct device, kobj);
97b6c217abSAndrew Lunn 	nvmem = to_nvmem_device(dev);
98b6c217abSAndrew Lunn 
99eace75cfSSrinivas Kandagatla 	/* Stop the user from reading */
1007c806883SZhengShunQian 	if (pos >= nvmem->size)
101eace75cfSSrinivas Kandagatla 		return 0;
102eace75cfSSrinivas Kandagatla 
103313a72ffSSrinivas Kandagatla 	if (count < nvmem->word_size)
104313a72ffSSrinivas Kandagatla 		return -EINVAL;
105313a72ffSSrinivas Kandagatla 
106eace75cfSSrinivas Kandagatla 	if (pos + count > nvmem->size)
107eace75cfSSrinivas Kandagatla 		count = nvmem->size - pos;
108eace75cfSSrinivas Kandagatla 
109eace75cfSSrinivas Kandagatla 	count = round_down(count, nvmem->word_size);
110eace75cfSSrinivas Kandagatla 
111795ddd18SSrinivas Kandagatla 	rc = nvmem_reg_read(nvmem, pos, buf, count);
112eace75cfSSrinivas Kandagatla 
113287980e4SArnd Bergmann 	if (rc)
114eace75cfSSrinivas Kandagatla 		return rc;
115eace75cfSSrinivas Kandagatla 
116eace75cfSSrinivas Kandagatla 	return count;
117eace75cfSSrinivas Kandagatla }
118eace75cfSSrinivas Kandagatla 
119eace75cfSSrinivas Kandagatla static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj,
120eace75cfSSrinivas Kandagatla 				     struct bin_attribute *attr,
121eace75cfSSrinivas Kandagatla 				     char *buf, loff_t pos, size_t count)
122eace75cfSSrinivas Kandagatla {
123b6c217abSAndrew Lunn 	struct device *dev;
124b6c217abSAndrew Lunn 	struct nvmem_device *nvmem;
125eace75cfSSrinivas Kandagatla 	int rc;
126eace75cfSSrinivas Kandagatla 
127b6c217abSAndrew Lunn 	if (attr->private)
128b6c217abSAndrew Lunn 		dev = attr->private;
129b6c217abSAndrew Lunn 	else
130b6c217abSAndrew Lunn 		dev = container_of(kobj, struct device, kobj);
131b6c217abSAndrew Lunn 	nvmem = to_nvmem_device(dev);
132b6c217abSAndrew Lunn 
133eace75cfSSrinivas Kandagatla 	/* Stop the user from writing */
1347c806883SZhengShunQian 	if (pos >= nvmem->size)
13538b0774cSGuy Shapiro 		return -EFBIG;
136eace75cfSSrinivas Kandagatla 
137313a72ffSSrinivas Kandagatla 	if (count < nvmem->word_size)
138313a72ffSSrinivas Kandagatla 		return -EINVAL;
139313a72ffSSrinivas Kandagatla 
140eace75cfSSrinivas Kandagatla 	if (pos + count > nvmem->size)
141eace75cfSSrinivas Kandagatla 		count = nvmem->size - pos;
142eace75cfSSrinivas Kandagatla 
143eace75cfSSrinivas Kandagatla 	count = round_down(count, nvmem->word_size);
144eace75cfSSrinivas Kandagatla 
145795ddd18SSrinivas Kandagatla 	rc = nvmem_reg_write(nvmem, pos, buf, count);
146eace75cfSSrinivas Kandagatla 
147287980e4SArnd Bergmann 	if (rc)
148eace75cfSSrinivas Kandagatla 		return rc;
149eace75cfSSrinivas Kandagatla 
150eace75cfSSrinivas Kandagatla 	return count;
151eace75cfSSrinivas Kandagatla }
152eace75cfSSrinivas Kandagatla 
153eace75cfSSrinivas Kandagatla /* default read/write permissions */
154eace75cfSSrinivas Kandagatla static struct bin_attribute bin_attr_rw_nvmem = {
155eace75cfSSrinivas Kandagatla 	.attr	= {
156eace75cfSSrinivas Kandagatla 		.name	= "nvmem",
157eace75cfSSrinivas Kandagatla 		.mode	= S_IWUSR | S_IRUGO,
158eace75cfSSrinivas Kandagatla 	},
159eace75cfSSrinivas Kandagatla 	.read	= bin_attr_nvmem_read,
160eace75cfSSrinivas Kandagatla 	.write	= bin_attr_nvmem_write,
161eace75cfSSrinivas Kandagatla };
162eace75cfSSrinivas Kandagatla 
163eace75cfSSrinivas Kandagatla static struct bin_attribute *nvmem_bin_rw_attributes[] = {
164eace75cfSSrinivas Kandagatla 	&bin_attr_rw_nvmem,
165eace75cfSSrinivas Kandagatla 	NULL,
166eace75cfSSrinivas Kandagatla };
167eace75cfSSrinivas Kandagatla 
168eace75cfSSrinivas Kandagatla static const struct attribute_group nvmem_bin_rw_group = {
169eace75cfSSrinivas Kandagatla 	.bin_attrs	= nvmem_bin_rw_attributes,
170eace75cfSSrinivas Kandagatla };
171eace75cfSSrinivas Kandagatla 
172eace75cfSSrinivas Kandagatla static const struct attribute_group *nvmem_rw_dev_groups[] = {
173eace75cfSSrinivas Kandagatla 	&nvmem_bin_rw_group,
174eace75cfSSrinivas Kandagatla 	NULL,
175eace75cfSSrinivas Kandagatla };
176eace75cfSSrinivas Kandagatla 
177eace75cfSSrinivas Kandagatla /* read only permission */
178eace75cfSSrinivas Kandagatla static struct bin_attribute bin_attr_ro_nvmem = {
179eace75cfSSrinivas Kandagatla 	.attr	= {
180eace75cfSSrinivas Kandagatla 		.name	= "nvmem",
181eace75cfSSrinivas Kandagatla 		.mode	= S_IRUGO,
182eace75cfSSrinivas Kandagatla 	},
183eace75cfSSrinivas Kandagatla 	.read	= bin_attr_nvmem_read,
184eace75cfSSrinivas Kandagatla };
185eace75cfSSrinivas Kandagatla 
186eace75cfSSrinivas Kandagatla static struct bin_attribute *nvmem_bin_ro_attributes[] = {
187eace75cfSSrinivas Kandagatla 	&bin_attr_ro_nvmem,
188eace75cfSSrinivas Kandagatla 	NULL,
189eace75cfSSrinivas Kandagatla };
190eace75cfSSrinivas Kandagatla 
191eace75cfSSrinivas Kandagatla static const struct attribute_group nvmem_bin_ro_group = {
192eace75cfSSrinivas Kandagatla 	.bin_attrs	= nvmem_bin_ro_attributes,
193eace75cfSSrinivas Kandagatla };
194eace75cfSSrinivas Kandagatla 
195eace75cfSSrinivas Kandagatla static const struct attribute_group *nvmem_ro_dev_groups[] = {
196eace75cfSSrinivas Kandagatla 	&nvmem_bin_ro_group,
197eace75cfSSrinivas Kandagatla 	NULL,
198eace75cfSSrinivas Kandagatla };
199eace75cfSSrinivas Kandagatla 
200811b0d65SAndrew Lunn /* default read/write permissions, root only */
201811b0d65SAndrew Lunn static struct bin_attribute bin_attr_rw_root_nvmem = {
202811b0d65SAndrew Lunn 	.attr	= {
203811b0d65SAndrew Lunn 		.name	= "nvmem",
204811b0d65SAndrew Lunn 		.mode	= S_IWUSR | S_IRUSR,
205811b0d65SAndrew Lunn 	},
206811b0d65SAndrew Lunn 	.read	= bin_attr_nvmem_read,
207811b0d65SAndrew Lunn 	.write	= bin_attr_nvmem_write,
208811b0d65SAndrew Lunn };
209811b0d65SAndrew Lunn 
210811b0d65SAndrew Lunn static struct bin_attribute *nvmem_bin_rw_root_attributes[] = {
211811b0d65SAndrew Lunn 	&bin_attr_rw_root_nvmem,
212811b0d65SAndrew Lunn 	NULL,
213811b0d65SAndrew Lunn };
214811b0d65SAndrew Lunn 
215811b0d65SAndrew Lunn static const struct attribute_group nvmem_bin_rw_root_group = {
216811b0d65SAndrew Lunn 	.bin_attrs	= nvmem_bin_rw_root_attributes,
217811b0d65SAndrew Lunn };
218811b0d65SAndrew Lunn 
219811b0d65SAndrew Lunn static const struct attribute_group *nvmem_rw_root_dev_groups[] = {
220811b0d65SAndrew Lunn 	&nvmem_bin_rw_root_group,
221811b0d65SAndrew Lunn 	NULL,
222811b0d65SAndrew Lunn };
223811b0d65SAndrew Lunn 
224811b0d65SAndrew Lunn /* read only permission, root only */
225811b0d65SAndrew Lunn static struct bin_attribute bin_attr_ro_root_nvmem = {
226811b0d65SAndrew Lunn 	.attr	= {
227811b0d65SAndrew Lunn 		.name	= "nvmem",
228811b0d65SAndrew Lunn 		.mode	= S_IRUSR,
229811b0d65SAndrew Lunn 	},
230811b0d65SAndrew Lunn 	.read	= bin_attr_nvmem_read,
231811b0d65SAndrew Lunn };
232811b0d65SAndrew Lunn 
233811b0d65SAndrew Lunn static struct bin_attribute *nvmem_bin_ro_root_attributes[] = {
234811b0d65SAndrew Lunn 	&bin_attr_ro_root_nvmem,
235811b0d65SAndrew Lunn 	NULL,
236811b0d65SAndrew Lunn };
237811b0d65SAndrew Lunn 
238811b0d65SAndrew Lunn static const struct attribute_group nvmem_bin_ro_root_group = {
239811b0d65SAndrew Lunn 	.bin_attrs	= nvmem_bin_ro_root_attributes,
240811b0d65SAndrew Lunn };
241811b0d65SAndrew Lunn 
242811b0d65SAndrew Lunn static const struct attribute_group *nvmem_ro_root_dev_groups[] = {
243811b0d65SAndrew Lunn 	&nvmem_bin_ro_root_group,
244811b0d65SAndrew Lunn 	NULL,
245811b0d65SAndrew Lunn };
246811b0d65SAndrew Lunn 
247eace75cfSSrinivas Kandagatla static void nvmem_release(struct device *dev)
248eace75cfSSrinivas Kandagatla {
249eace75cfSSrinivas Kandagatla 	struct nvmem_device *nvmem = to_nvmem_device(dev);
250eace75cfSSrinivas Kandagatla 
251eace75cfSSrinivas Kandagatla 	ida_simple_remove(&nvmem_ida, nvmem->id);
252eace75cfSSrinivas Kandagatla 	kfree(nvmem);
253eace75cfSSrinivas Kandagatla }
254eace75cfSSrinivas Kandagatla 
255eace75cfSSrinivas Kandagatla static const struct device_type nvmem_provider_type = {
256eace75cfSSrinivas Kandagatla 	.release	= nvmem_release,
257eace75cfSSrinivas Kandagatla };
258eace75cfSSrinivas Kandagatla 
259eace75cfSSrinivas Kandagatla static struct bus_type nvmem_bus_type = {
260eace75cfSSrinivas Kandagatla 	.name		= "nvmem",
261eace75cfSSrinivas Kandagatla };
262eace75cfSSrinivas Kandagatla 
263eace75cfSSrinivas Kandagatla static int of_nvmem_match(struct device *dev, void *nvmem_np)
264eace75cfSSrinivas Kandagatla {
265eace75cfSSrinivas Kandagatla 	return dev->of_node == nvmem_np;
266eace75cfSSrinivas Kandagatla }
267eace75cfSSrinivas Kandagatla 
268eace75cfSSrinivas Kandagatla static struct nvmem_device *of_nvmem_find(struct device_node *nvmem_np)
269eace75cfSSrinivas Kandagatla {
270eace75cfSSrinivas Kandagatla 	struct device *d;
271eace75cfSSrinivas Kandagatla 
272eace75cfSSrinivas Kandagatla 	if (!nvmem_np)
273eace75cfSSrinivas Kandagatla 		return NULL;
274eace75cfSSrinivas Kandagatla 
275eace75cfSSrinivas Kandagatla 	d = bus_find_device(&nvmem_bus_type, NULL, nvmem_np, of_nvmem_match);
276eace75cfSSrinivas Kandagatla 
277eace75cfSSrinivas Kandagatla 	if (!d)
278eace75cfSSrinivas Kandagatla 		return NULL;
279eace75cfSSrinivas Kandagatla 
280eace75cfSSrinivas Kandagatla 	return to_nvmem_device(d);
281eace75cfSSrinivas Kandagatla }
282eace75cfSSrinivas Kandagatla 
283506157beSBartosz Golaszewski static struct nvmem_device *nvmem_find(const char *name)
284506157beSBartosz Golaszewski {
285506157beSBartosz Golaszewski 	struct device *d;
286506157beSBartosz Golaszewski 
287506157beSBartosz Golaszewski 	d = bus_find_device_by_name(&nvmem_bus_type, NULL, name);
288506157beSBartosz Golaszewski 
289506157beSBartosz Golaszewski 	if (!d)
290506157beSBartosz Golaszewski 		return NULL;
291506157beSBartosz Golaszewski 
292506157beSBartosz Golaszewski 	return to_nvmem_device(d);
293506157beSBartosz Golaszewski }
294506157beSBartosz Golaszewski 
295eace75cfSSrinivas Kandagatla static void nvmem_cell_drop(struct nvmem_cell *cell)
296eace75cfSSrinivas Kandagatla {
297bee1138bSBartosz Golaszewski 	blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_REMOVE, cell);
298c7235ee3SBartosz Golaszewski 	mutex_lock(&nvmem_mutex);
299eace75cfSSrinivas Kandagatla 	list_del(&cell->node);
300c7235ee3SBartosz Golaszewski 	mutex_unlock(&nvmem_mutex);
301eace75cfSSrinivas Kandagatla 	kfree(cell);
302eace75cfSSrinivas Kandagatla }
303eace75cfSSrinivas Kandagatla 
304eace75cfSSrinivas Kandagatla static void nvmem_device_remove_all_cells(const struct nvmem_device *nvmem)
305eace75cfSSrinivas Kandagatla {
3061852183eSBartosz Golaszewski 	struct nvmem_cell *cell, *p;
307eace75cfSSrinivas Kandagatla 
308c7235ee3SBartosz Golaszewski 	list_for_each_entry_safe(cell, p, &nvmem->cells, node)
309eace75cfSSrinivas Kandagatla 		nvmem_cell_drop(cell);
310eace75cfSSrinivas Kandagatla }
311eace75cfSSrinivas Kandagatla 
312eace75cfSSrinivas Kandagatla static void nvmem_cell_add(struct nvmem_cell *cell)
313eace75cfSSrinivas Kandagatla {
314c7235ee3SBartosz Golaszewski 	mutex_lock(&nvmem_mutex);
315c7235ee3SBartosz Golaszewski 	list_add_tail(&cell->node, &cell->nvmem->cells);
316c7235ee3SBartosz Golaszewski 	mutex_unlock(&nvmem_mutex);
317bee1138bSBartosz Golaszewski 	blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_ADD, cell);
318eace75cfSSrinivas Kandagatla }
319eace75cfSSrinivas Kandagatla 
320eace75cfSSrinivas Kandagatla static int nvmem_cell_info_to_nvmem_cell(struct nvmem_device *nvmem,
321eace75cfSSrinivas Kandagatla 				   const struct nvmem_cell_info *info,
322eace75cfSSrinivas Kandagatla 				   struct nvmem_cell *cell)
323eace75cfSSrinivas Kandagatla {
324eace75cfSSrinivas Kandagatla 	cell->nvmem = nvmem;
325eace75cfSSrinivas Kandagatla 	cell->offset = info->offset;
326eace75cfSSrinivas Kandagatla 	cell->bytes = info->bytes;
327eace75cfSSrinivas Kandagatla 	cell->name = info->name;
328eace75cfSSrinivas Kandagatla 
329eace75cfSSrinivas Kandagatla 	cell->bit_offset = info->bit_offset;
330eace75cfSSrinivas Kandagatla 	cell->nbits = info->nbits;
331eace75cfSSrinivas Kandagatla 
332eace75cfSSrinivas Kandagatla 	if (cell->nbits)
333eace75cfSSrinivas Kandagatla 		cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset,
334eace75cfSSrinivas Kandagatla 					   BITS_PER_BYTE);
335eace75cfSSrinivas Kandagatla 
336eace75cfSSrinivas Kandagatla 	if (!IS_ALIGNED(cell->offset, nvmem->stride)) {
337eace75cfSSrinivas Kandagatla 		dev_err(&nvmem->dev,
338eace75cfSSrinivas Kandagatla 			"cell %s unaligned to nvmem stride %d\n",
339eace75cfSSrinivas Kandagatla 			cell->name, nvmem->stride);
340eace75cfSSrinivas Kandagatla 		return -EINVAL;
341eace75cfSSrinivas Kandagatla 	}
342eace75cfSSrinivas Kandagatla 
343eace75cfSSrinivas Kandagatla 	return 0;
344eace75cfSSrinivas Kandagatla }
345eace75cfSSrinivas Kandagatla 
346b3db17e4SAndrew Lunn /**
347b3db17e4SAndrew Lunn  * nvmem_add_cells() - Add cell information to an nvmem device
348b3db17e4SAndrew Lunn  *
349b3db17e4SAndrew Lunn  * @nvmem: nvmem device to add cells to.
350b3db17e4SAndrew Lunn  * @info: nvmem cell info to add to the device
351b3db17e4SAndrew Lunn  * @ncells: number of cells in info
352b3db17e4SAndrew Lunn  *
353b3db17e4SAndrew Lunn  * Return: 0 or negative error code on failure.
354b3db17e4SAndrew Lunn  */
355b3db17e4SAndrew Lunn int nvmem_add_cells(struct nvmem_device *nvmem,
356b3db17e4SAndrew Lunn 		    const struct nvmem_cell_info *info,
357b3db17e4SAndrew Lunn 		    int ncells)
358eace75cfSSrinivas Kandagatla {
359eace75cfSSrinivas Kandagatla 	struct nvmem_cell **cells;
360eace75cfSSrinivas Kandagatla 	int i, rval;
361eace75cfSSrinivas Kandagatla 
362b3db17e4SAndrew Lunn 	cells = kcalloc(ncells, sizeof(*cells), GFP_KERNEL);
363eace75cfSSrinivas Kandagatla 	if (!cells)
364eace75cfSSrinivas Kandagatla 		return -ENOMEM;
365eace75cfSSrinivas Kandagatla 
366b3db17e4SAndrew Lunn 	for (i = 0; i < ncells; i++) {
367eace75cfSSrinivas Kandagatla 		cells[i] = kzalloc(sizeof(**cells), GFP_KERNEL);
368eace75cfSSrinivas Kandagatla 		if (!cells[i]) {
369eace75cfSSrinivas Kandagatla 			rval = -ENOMEM;
370eace75cfSSrinivas Kandagatla 			goto err;
371eace75cfSSrinivas Kandagatla 		}
372eace75cfSSrinivas Kandagatla 
373eace75cfSSrinivas Kandagatla 		rval = nvmem_cell_info_to_nvmem_cell(nvmem, &info[i], cells[i]);
374287980e4SArnd Bergmann 		if (rval) {
375eace75cfSSrinivas Kandagatla 			kfree(cells[i]);
376eace75cfSSrinivas Kandagatla 			goto err;
377eace75cfSSrinivas Kandagatla 		}
378eace75cfSSrinivas Kandagatla 
379eace75cfSSrinivas Kandagatla 		nvmem_cell_add(cells[i]);
380eace75cfSSrinivas Kandagatla 	}
381eace75cfSSrinivas Kandagatla 
382eace75cfSSrinivas Kandagatla 	/* remove tmp array */
383eace75cfSSrinivas Kandagatla 	kfree(cells);
384eace75cfSSrinivas Kandagatla 
385eace75cfSSrinivas Kandagatla 	return 0;
386eace75cfSSrinivas Kandagatla err:
387dfdf1414SRasmus Villemoes 	while (i--)
388eace75cfSSrinivas Kandagatla 		nvmem_cell_drop(cells[i]);
389eace75cfSSrinivas Kandagatla 
390dfdf1414SRasmus Villemoes 	kfree(cells);
391dfdf1414SRasmus Villemoes 
392eace75cfSSrinivas Kandagatla 	return rval;
393eace75cfSSrinivas Kandagatla }
394b3db17e4SAndrew Lunn EXPORT_SYMBOL_GPL(nvmem_add_cells);
395eace75cfSSrinivas Kandagatla 
396b6c217abSAndrew Lunn /*
397b6c217abSAndrew Lunn  * nvmem_setup_compat() - Create an additional binary entry in
398b6c217abSAndrew Lunn  * drivers sys directory, to be backwards compatible with the older
399b6c217abSAndrew Lunn  * drivers/misc/eeprom drivers.
400b6c217abSAndrew Lunn  */
401b6c217abSAndrew Lunn static int nvmem_setup_compat(struct nvmem_device *nvmem,
402b6c217abSAndrew Lunn 			      const struct nvmem_config *config)
403b6c217abSAndrew Lunn {
404b6c217abSAndrew Lunn 	int rval;
405b6c217abSAndrew Lunn 
406b6c217abSAndrew Lunn 	if (!config->base_dev)
407b6c217abSAndrew Lunn 		return -EINVAL;
408b6c217abSAndrew Lunn 
409b6c217abSAndrew Lunn 	if (nvmem->read_only)
410b6c217abSAndrew Lunn 		nvmem->eeprom = bin_attr_ro_root_nvmem;
411b6c217abSAndrew Lunn 	else
412b6c217abSAndrew Lunn 		nvmem->eeprom = bin_attr_rw_root_nvmem;
413b6c217abSAndrew Lunn 	nvmem->eeprom.attr.name = "eeprom";
414b6c217abSAndrew Lunn 	nvmem->eeprom.size = nvmem->size;
415b6c217abSAndrew Lunn #ifdef CONFIG_DEBUG_LOCK_ALLOC
416b6c217abSAndrew Lunn 	nvmem->eeprom.attr.key = &eeprom_lock_key;
417b6c217abSAndrew Lunn #endif
418b6c217abSAndrew Lunn 	nvmem->eeprom.private = &nvmem->dev;
419b6c217abSAndrew Lunn 	nvmem->base_dev = config->base_dev;
420b6c217abSAndrew Lunn 
421b6c217abSAndrew Lunn 	rval = device_create_bin_file(nvmem->base_dev, &nvmem->eeprom);
422b6c217abSAndrew Lunn 	if (rval) {
423b6c217abSAndrew Lunn 		dev_err(&nvmem->dev,
424b6c217abSAndrew Lunn 			"Failed to create eeprom binary file %d\n", rval);
425b6c217abSAndrew Lunn 		return rval;
426b6c217abSAndrew Lunn 	}
427b6c217abSAndrew Lunn 
428b6c217abSAndrew Lunn 	nvmem->flags |= FLAG_COMPAT;
429b6c217abSAndrew Lunn 
430b6c217abSAndrew Lunn 	return 0;
431b6c217abSAndrew Lunn }
432b6c217abSAndrew Lunn 
433bee1138bSBartosz Golaszewski /**
434bee1138bSBartosz Golaszewski  * nvmem_register_notifier() - Register a notifier block for nvmem events.
435bee1138bSBartosz Golaszewski  *
436bee1138bSBartosz Golaszewski  * @nb: notifier block to be called on nvmem events.
437bee1138bSBartosz Golaszewski  *
438bee1138bSBartosz Golaszewski  * Return: 0 on success, negative error number on failure.
439bee1138bSBartosz Golaszewski  */
440bee1138bSBartosz Golaszewski int nvmem_register_notifier(struct notifier_block *nb)
441bee1138bSBartosz Golaszewski {
442bee1138bSBartosz Golaszewski 	return blocking_notifier_chain_register(&nvmem_notifier, nb);
443bee1138bSBartosz Golaszewski }
444bee1138bSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_register_notifier);
445bee1138bSBartosz Golaszewski 
446bee1138bSBartosz Golaszewski /**
447bee1138bSBartosz Golaszewski  * nvmem_unregister_notifier() - Unregister a notifier block for nvmem events.
448bee1138bSBartosz Golaszewski  *
449bee1138bSBartosz Golaszewski  * @nb: notifier block to be unregistered.
450bee1138bSBartosz Golaszewski  *
451bee1138bSBartosz Golaszewski  * Return: 0 on success, negative error number on failure.
452bee1138bSBartosz Golaszewski  */
453bee1138bSBartosz Golaszewski int nvmem_unregister_notifier(struct notifier_block *nb)
454bee1138bSBartosz Golaszewski {
455bee1138bSBartosz Golaszewski 	return blocking_notifier_chain_unregister(&nvmem_notifier, nb);
456bee1138bSBartosz Golaszewski }
457bee1138bSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_unregister_notifier);
458bee1138bSBartosz Golaszewski 
459b985f4cbSBartosz Golaszewski static int nvmem_add_cells_from_table(struct nvmem_device *nvmem)
460b985f4cbSBartosz Golaszewski {
461b985f4cbSBartosz Golaszewski 	const struct nvmem_cell_info *info;
462b985f4cbSBartosz Golaszewski 	struct nvmem_cell_table *table;
463b985f4cbSBartosz Golaszewski 	struct nvmem_cell *cell;
464b985f4cbSBartosz Golaszewski 	int rval = 0, i;
465b985f4cbSBartosz Golaszewski 
466b985f4cbSBartosz Golaszewski 	mutex_lock(&nvmem_cell_mutex);
467b985f4cbSBartosz Golaszewski 	list_for_each_entry(table, &nvmem_cell_tables, node) {
468b985f4cbSBartosz Golaszewski 		if (strcmp(nvmem_dev_name(nvmem), table->nvmem_name) == 0) {
469b985f4cbSBartosz Golaszewski 			for (i = 0; i < table->ncells; i++) {
470b985f4cbSBartosz Golaszewski 				info = &table->cells[i];
471b985f4cbSBartosz Golaszewski 
472b985f4cbSBartosz Golaszewski 				cell = kzalloc(sizeof(*cell), GFP_KERNEL);
473b985f4cbSBartosz Golaszewski 				if (!cell) {
474b985f4cbSBartosz Golaszewski 					rval = -ENOMEM;
475b985f4cbSBartosz Golaszewski 					goto out;
476b985f4cbSBartosz Golaszewski 				}
477b985f4cbSBartosz Golaszewski 
478b985f4cbSBartosz Golaszewski 				rval = nvmem_cell_info_to_nvmem_cell(nvmem,
479b985f4cbSBartosz Golaszewski 								     info,
480b985f4cbSBartosz Golaszewski 								     cell);
481b985f4cbSBartosz Golaszewski 				if (rval) {
482b985f4cbSBartosz Golaszewski 					kfree(cell);
483b985f4cbSBartosz Golaszewski 					goto out;
484b985f4cbSBartosz Golaszewski 				}
485b985f4cbSBartosz Golaszewski 
486b985f4cbSBartosz Golaszewski 				nvmem_cell_add(cell);
487b985f4cbSBartosz Golaszewski 			}
488b985f4cbSBartosz Golaszewski 		}
489b985f4cbSBartosz Golaszewski 	}
490b985f4cbSBartosz Golaszewski 
491b985f4cbSBartosz Golaszewski out:
492b985f4cbSBartosz Golaszewski 	mutex_unlock(&nvmem_cell_mutex);
493b985f4cbSBartosz Golaszewski 	return rval;
494b985f4cbSBartosz Golaszewski }
495b985f4cbSBartosz Golaszewski 
496e888d445SBartosz Golaszewski static struct nvmem_cell *
497e888d445SBartosz Golaszewski nvmem_find_cell_by_index(struct nvmem_device *nvmem, int index)
498e888d445SBartosz Golaszewski {
499e888d445SBartosz Golaszewski 	struct nvmem_cell *cell = NULL;
500e888d445SBartosz Golaszewski 	int i = 0;
501e888d445SBartosz Golaszewski 
502e888d445SBartosz Golaszewski 	mutex_lock(&nvmem_mutex);
503e888d445SBartosz Golaszewski 	list_for_each_entry(cell, &nvmem->cells, node) {
504e888d445SBartosz Golaszewski 		if (index == i++)
505e888d445SBartosz Golaszewski 			break;
506e888d445SBartosz Golaszewski 	}
507e888d445SBartosz Golaszewski 	mutex_unlock(&nvmem_mutex);
508e888d445SBartosz Golaszewski 
509e888d445SBartosz Golaszewski 	return cell;
510e888d445SBartosz Golaszewski }
511e888d445SBartosz Golaszewski 
512506157beSBartosz Golaszewski static struct nvmem_cell *
513506157beSBartosz Golaszewski nvmem_find_cell_by_name(struct nvmem_device *nvmem, const char *cell_id)
514506157beSBartosz Golaszewski {
515506157beSBartosz Golaszewski 	struct nvmem_cell *cell = NULL;
516506157beSBartosz Golaszewski 
517506157beSBartosz Golaszewski 	mutex_lock(&nvmem_mutex);
518506157beSBartosz Golaszewski 	list_for_each_entry(cell, &nvmem->cells, node) {
519506157beSBartosz Golaszewski 		if (strcmp(cell_id, cell->name) == 0)
520506157beSBartosz Golaszewski 			break;
521506157beSBartosz Golaszewski 	}
522506157beSBartosz Golaszewski 	mutex_unlock(&nvmem_mutex);
523506157beSBartosz Golaszewski 
524506157beSBartosz Golaszewski 	return cell;
525506157beSBartosz Golaszewski }
526506157beSBartosz Golaszewski 
527e888d445SBartosz Golaszewski static int nvmem_add_cells_from_of(struct nvmem_device *nvmem)
528e888d445SBartosz Golaszewski {
529e888d445SBartosz Golaszewski 	struct device_node *parent, *child;
530e888d445SBartosz Golaszewski 	struct device *dev = &nvmem->dev;
531e888d445SBartosz Golaszewski 	struct nvmem_cell *cell;
532e888d445SBartosz Golaszewski 	const __be32 *addr;
533e888d445SBartosz Golaszewski 	int len;
534e888d445SBartosz Golaszewski 
535e888d445SBartosz Golaszewski 	parent = dev->of_node;
536e888d445SBartosz Golaszewski 
537e888d445SBartosz Golaszewski 	for_each_child_of_node(parent, child) {
538e888d445SBartosz Golaszewski 		addr = of_get_property(child, "reg", &len);
539e888d445SBartosz Golaszewski 		if (!addr || (len < 2 * sizeof(u32))) {
540e888d445SBartosz Golaszewski 			dev_err(dev, "nvmem: invalid reg on %pOF\n", child);
541e888d445SBartosz Golaszewski 			return -EINVAL;
542e888d445SBartosz Golaszewski 		}
543e888d445SBartosz Golaszewski 
544e888d445SBartosz Golaszewski 		cell = kzalloc(sizeof(*cell), GFP_KERNEL);
545e888d445SBartosz Golaszewski 		if (!cell)
546e888d445SBartosz Golaszewski 			return -ENOMEM;
547e888d445SBartosz Golaszewski 
548e888d445SBartosz Golaszewski 		cell->nvmem = nvmem;
549e888d445SBartosz Golaszewski 		cell->offset = be32_to_cpup(addr++);
550e888d445SBartosz Golaszewski 		cell->bytes = be32_to_cpup(addr);
551e888d445SBartosz Golaszewski 		cell->name = child->name;
552e888d445SBartosz Golaszewski 
553e888d445SBartosz Golaszewski 		addr = of_get_property(child, "bits", &len);
554e888d445SBartosz Golaszewski 		if (addr && len == (2 * sizeof(u32))) {
555e888d445SBartosz Golaszewski 			cell->bit_offset = be32_to_cpup(addr++);
556e888d445SBartosz Golaszewski 			cell->nbits = be32_to_cpup(addr);
557e888d445SBartosz Golaszewski 		}
558e888d445SBartosz Golaszewski 
559e888d445SBartosz Golaszewski 		if (cell->nbits)
560e888d445SBartosz Golaszewski 			cell->bytes = DIV_ROUND_UP(
561e888d445SBartosz Golaszewski 					cell->nbits + cell->bit_offset,
562e888d445SBartosz Golaszewski 					BITS_PER_BYTE);
563e888d445SBartosz Golaszewski 
564e888d445SBartosz Golaszewski 		if (!IS_ALIGNED(cell->offset, nvmem->stride)) {
565e888d445SBartosz Golaszewski 			dev_err(dev, "cell %s unaligned to nvmem stride %d\n",
566e888d445SBartosz Golaszewski 				cell->name, nvmem->stride);
567e888d445SBartosz Golaszewski 			/* Cells already added will be freed later. */
568e888d445SBartosz Golaszewski 			kfree(cell);
569e888d445SBartosz Golaszewski 			return -EINVAL;
570e888d445SBartosz Golaszewski 		}
571e888d445SBartosz Golaszewski 
572e888d445SBartosz Golaszewski 		nvmem_cell_add(cell);
573e888d445SBartosz Golaszewski 	}
574e888d445SBartosz Golaszewski 
575e888d445SBartosz Golaszewski 	return 0;
576e888d445SBartosz Golaszewski }
577e888d445SBartosz Golaszewski 
578eace75cfSSrinivas Kandagatla /**
579eace75cfSSrinivas Kandagatla  * nvmem_register() - Register a nvmem device for given nvmem_config.
580eace75cfSSrinivas Kandagatla  * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem
581eace75cfSSrinivas Kandagatla  *
582eace75cfSSrinivas Kandagatla  * @config: nvmem device configuration with which nvmem device is created.
583eace75cfSSrinivas Kandagatla  *
584eace75cfSSrinivas Kandagatla  * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device
585eace75cfSSrinivas Kandagatla  * on success.
586eace75cfSSrinivas Kandagatla  */
587eace75cfSSrinivas Kandagatla 
588eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem_register(const struct nvmem_config *config)
589eace75cfSSrinivas Kandagatla {
590eace75cfSSrinivas Kandagatla 	struct nvmem_device *nvmem;
591eace75cfSSrinivas Kandagatla 	int rval;
592eace75cfSSrinivas Kandagatla 
593eace75cfSSrinivas Kandagatla 	if (!config->dev)
594eace75cfSSrinivas Kandagatla 		return ERR_PTR(-EINVAL);
595eace75cfSSrinivas Kandagatla 
596eace75cfSSrinivas Kandagatla 	nvmem = kzalloc(sizeof(*nvmem), GFP_KERNEL);
597eace75cfSSrinivas Kandagatla 	if (!nvmem)
598eace75cfSSrinivas Kandagatla 		return ERR_PTR(-ENOMEM);
599eace75cfSSrinivas Kandagatla 
600eace75cfSSrinivas Kandagatla 	rval  = ida_simple_get(&nvmem_ida, 0, 0, GFP_KERNEL);
601eace75cfSSrinivas Kandagatla 	if (rval < 0) {
602eace75cfSSrinivas Kandagatla 		kfree(nvmem);
603eace75cfSSrinivas Kandagatla 		return ERR_PTR(rval);
604eace75cfSSrinivas Kandagatla 	}
605eace75cfSSrinivas Kandagatla 
606c1de7f43SBartosz Golaszewski 	kref_init(&nvmem->refcnt);
607c7235ee3SBartosz Golaszewski 	INIT_LIST_HEAD(&nvmem->cells);
608c1de7f43SBartosz Golaszewski 
609eace75cfSSrinivas Kandagatla 	nvmem->id = rval;
610eace75cfSSrinivas Kandagatla 	nvmem->owner = config->owner;
61117eb18d6SMasahiro Yamada 	if (!nvmem->owner && config->dev->driver)
61217eb18d6SMasahiro Yamada 		nvmem->owner = config->dev->driver->owner;
61399897efdSHeiner Kallweit 	nvmem->stride = config->stride ?: 1;
61499897efdSHeiner Kallweit 	nvmem->word_size = config->word_size ?: 1;
615795ddd18SSrinivas Kandagatla 	nvmem->size = config->size;
616eace75cfSSrinivas Kandagatla 	nvmem->dev.type = &nvmem_provider_type;
617eace75cfSSrinivas Kandagatla 	nvmem->dev.bus = &nvmem_bus_type;
618eace75cfSSrinivas Kandagatla 	nvmem->dev.parent = config->dev;
619795ddd18SSrinivas Kandagatla 	nvmem->priv = config->priv;
620795ddd18SSrinivas Kandagatla 	nvmem->reg_read = config->reg_read;
621795ddd18SSrinivas Kandagatla 	nvmem->reg_write = config->reg_write;
622fc2f9970SHeiner Kallweit 	nvmem->dev.of_node = config->dev->of_node;
623fd0f4906SAndrey Smirnov 
624fd0f4906SAndrey Smirnov 	if (config->id == -1 && config->name) {
625fd0f4906SAndrey Smirnov 		dev_set_name(&nvmem->dev, "%s", config->name);
626fd0f4906SAndrey Smirnov 	} else {
627eace75cfSSrinivas Kandagatla 		dev_set_name(&nvmem->dev, "%s%d",
6285253193dSAban Bedel 			     config->name ? : "nvmem",
6295253193dSAban Bedel 			     config->name ? config->id : nvmem->id);
630fd0f4906SAndrey Smirnov 	}
631eace75cfSSrinivas Kandagatla 
632fc2f9970SHeiner Kallweit 	nvmem->read_only = device_property_present(config->dev, "read-only") |
633eace75cfSSrinivas Kandagatla 			   config->read_only;
634eace75cfSSrinivas Kandagatla 
635811b0d65SAndrew Lunn 	if (config->root_only)
636811b0d65SAndrew Lunn 		nvmem->dev.groups = nvmem->read_only ?
637811b0d65SAndrew Lunn 			nvmem_ro_root_dev_groups :
638811b0d65SAndrew Lunn 			nvmem_rw_root_dev_groups;
639811b0d65SAndrew Lunn 	else
640811b0d65SAndrew Lunn 		nvmem->dev.groups = nvmem->read_only ?
641811b0d65SAndrew Lunn 			nvmem_ro_dev_groups :
642eace75cfSSrinivas Kandagatla 			nvmem_rw_dev_groups;
643eace75cfSSrinivas Kandagatla 
644eace75cfSSrinivas Kandagatla 	device_initialize(&nvmem->dev);
645eace75cfSSrinivas Kandagatla 
646eace75cfSSrinivas Kandagatla 	dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name);
647eace75cfSSrinivas Kandagatla 
648eace75cfSSrinivas Kandagatla 	rval = device_add(&nvmem->dev);
649b6c217abSAndrew Lunn 	if (rval)
6503360acdfSJohan Hovold 		goto err_put_device;
651b6c217abSAndrew Lunn 
652b6c217abSAndrew Lunn 	if (config->compat) {
653b6c217abSAndrew Lunn 		rval = nvmem_setup_compat(nvmem, config);
654b6c217abSAndrew Lunn 		if (rval)
6553360acdfSJohan Hovold 			goto err_device_del;
656eace75cfSSrinivas Kandagatla 	}
657eace75cfSSrinivas Kandagatla 
658fa72d847SBartosz Golaszewski 	if (config->cells) {
659fa72d847SBartosz Golaszewski 		rval = nvmem_add_cells(nvmem, config->cells, config->ncells);
660fa72d847SBartosz Golaszewski 		if (rval)
661fa72d847SBartosz Golaszewski 			goto err_teardown_compat;
662fa72d847SBartosz Golaszewski 	}
663eace75cfSSrinivas Kandagatla 
664b985f4cbSBartosz Golaszewski 	rval = nvmem_add_cells_from_table(nvmem);
665b985f4cbSBartosz Golaszewski 	if (rval)
666b985f4cbSBartosz Golaszewski 		goto err_remove_cells;
667b985f4cbSBartosz Golaszewski 
668e888d445SBartosz Golaszewski 	rval = nvmem_add_cells_from_of(nvmem);
669e888d445SBartosz Golaszewski 	if (rval)
670e888d445SBartosz Golaszewski 		goto err_remove_cells;
671e888d445SBartosz Golaszewski 
672bee1138bSBartosz Golaszewski 	rval = blocking_notifier_call_chain(&nvmem_notifier, NVMEM_ADD, nvmem);
673bee1138bSBartosz Golaszewski 	if (rval)
674bee1138bSBartosz Golaszewski 		goto err_remove_cells;
675bee1138bSBartosz Golaszewski 
676eace75cfSSrinivas Kandagatla 	return nvmem;
6773360acdfSJohan Hovold 
678b985f4cbSBartosz Golaszewski err_remove_cells:
679b985f4cbSBartosz Golaszewski 	nvmem_device_remove_all_cells(nvmem);
680fa72d847SBartosz Golaszewski err_teardown_compat:
681fa72d847SBartosz Golaszewski 	if (config->compat)
682fa72d847SBartosz Golaszewski 		device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom);
6833360acdfSJohan Hovold err_device_del:
6843360acdfSJohan Hovold 	device_del(&nvmem->dev);
6853360acdfSJohan Hovold err_put_device:
6863360acdfSJohan Hovold 	put_device(&nvmem->dev);
6873360acdfSJohan Hovold 
688b6c217abSAndrew Lunn 	return ERR_PTR(rval);
689eace75cfSSrinivas Kandagatla }
690eace75cfSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_register);
691eace75cfSSrinivas Kandagatla 
692c1de7f43SBartosz Golaszewski static void nvmem_device_release(struct kref *kref)
693c1de7f43SBartosz Golaszewski {
694c1de7f43SBartosz Golaszewski 	struct nvmem_device *nvmem;
695c1de7f43SBartosz Golaszewski 
696c1de7f43SBartosz Golaszewski 	nvmem = container_of(kref, struct nvmem_device, refcnt);
697c1de7f43SBartosz Golaszewski 
698bee1138bSBartosz Golaszewski 	blocking_notifier_call_chain(&nvmem_notifier, NVMEM_REMOVE, nvmem);
699bee1138bSBartosz Golaszewski 
700c1de7f43SBartosz Golaszewski 	if (nvmem->flags & FLAG_COMPAT)
701c1de7f43SBartosz Golaszewski 		device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom);
702c1de7f43SBartosz Golaszewski 
703c1de7f43SBartosz Golaszewski 	nvmem_device_remove_all_cells(nvmem);
704c1de7f43SBartosz Golaszewski 	device_del(&nvmem->dev);
705c1de7f43SBartosz Golaszewski 	put_device(&nvmem->dev);
706c1de7f43SBartosz Golaszewski }
707c1de7f43SBartosz Golaszewski 
708eace75cfSSrinivas Kandagatla /**
709eace75cfSSrinivas Kandagatla  * nvmem_unregister() - Unregister previously registered nvmem device
710eace75cfSSrinivas Kandagatla  *
711eace75cfSSrinivas Kandagatla  * @nvmem: Pointer to previously registered nvmem device.
712eace75cfSSrinivas Kandagatla  */
713bf58e882SBartosz Golaszewski void nvmem_unregister(struct nvmem_device *nvmem)
714eace75cfSSrinivas Kandagatla {
715c1de7f43SBartosz Golaszewski 	kref_put(&nvmem->refcnt, nvmem_device_release);
716eace75cfSSrinivas Kandagatla }
717eace75cfSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_unregister);
718eace75cfSSrinivas Kandagatla 
719f1f50ecaSAndrey Smirnov static void devm_nvmem_release(struct device *dev, void *res)
720f1f50ecaSAndrey Smirnov {
721bf58e882SBartosz Golaszewski 	nvmem_unregister(*(struct nvmem_device **)res);
722f1f50ecaSAndrey Smirnov }
723f1f50ecaSAndrey Smirnov 
724f1f50ecaSAndrey Smirnov /**
725f1f50ecaSAndrey Smirnov  * devm_nvmem_register() - Register a managed nvmem device for given
726f1f50ecaSAndrey Smirnov  * nvmem_config.
727f1f50ecaSAndrey Smirnov  * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem
728f1f50ecaSAndrey Smirnov  *
729b378c779SSrinivas Kandagatla  * @dev: Device that uses the nvmem device.
730f1f50ecaSAndrey Smirnov  * @config: nvmem device configuration with which nvmem device is created.
731f1f50ecaSAndrey Smirnov  *
732f1f50ecaSAndrey Smirnov  * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device
733f1f50ecaSAndrey Smirnov  * on success.
734f1f50ecaSAndrey Smirnov  */
735f1f50ecaSAndrey Smirnov struct nvmem_device *devm_nvmem_register(struct device *dev,
736f1f50ecaSAndrey Smirnov 					 const struct nvmem_config *config)
737f1f50ecaSAndrey Smirnov {
738f1f50ecaSAndrey Smirnov 	struct nvmem_device **ptr, *nvmem;
739f1f50ecaSAndrey Smirnov 
740f1f50ecaSAndrey Smirnov 	ptr = devres_alloc(devm_nvmem_release, sizeof(*ptr), GFP_KERNEL);
741f1f50ecaSAndrey Smirnov 	if (!ptr)
742f1f50ecaSAndrey Smirnov 		return ERR_PTR(-ENOMEM);
743f1f50ecaSAndrey Smirnov 
744f1f50ecaSAndrey Smirnov 	nvmem = nvmem_register(config);
745f1f50ecaSAndrey Smirnov 
746f1f50ecaSAndrey Smirnov 	if (!IS_ERR(nvmem)) {
747f1f50ecaSAndrey Smirnov 		*ptr = nvmem;
748f1f50ecaSAndrey Smirnov 		devres_add(dev, ptr);
749f1f50ecaSAndrey Smirnov 	} else {
750f1f50ecaSAndrey Smirnov 		devres_free(ptr);
751f1f50ecaSAndrey Smirnov 	}
752f1f50ecaSAndrey Smirnov 
753f1f50ecaSAndrey Smirnov 	return nvmem;
754f1f50ecaSAndrey Smirnov }
755f1f50ecaSAndrey Smirnov EXPORT_SYMBOL_GPL(devm_nvmem_register);
756f1f50ecaSAndrey Smirnov 
757f1f50ecaSAndrey Smirnov static int devm_nvmem_match(struct device *dev, void *res, void *data)
758f1f50ecaSAndrey Smirnov {
759f1f50ecaSAndrey Smirnov 	struct nvmem_device **r = res;
760f1f50ecaSAndrey Smirnov 
761f1f50ecaSAndrey Smirnov 	return *r == data;
762f1f50ecaSAndrey Smirnov }
763f1f50ecaSAndrey Smirnov 
764f1f50ecaSAndrey Smirnov /**
765f1f50ecaSAndrey Smirnov  * devm_nvmem_unregister() - Unregister previously registered managed nvmem
766f1f50ecaSAndrey Smirnov  * device.
767f1f50ecaSAndrey Smirnov  *
768b378c779SSrinivas Kandagatla  * @dev: Device that uses the nvmem device.
769f1f50ecaSAndrey Smirnov  * @nvmem: Pointer to previously registered nvmem device.
770f1f50ecaSAndrey Smirnov  *
771f1f50ecaSAndrey Smirnov  * Return: Will be an negative on error or a zero on success.
772f1f50ecaSAndrey Smirnov  */
773f1f50ecaSAndrey Smirnov int devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem)
774f1f50ecaSAndrey Smirnov {
775f1f50ecaSAndrey Smirnov 	return devres_release(dev, devm_nvmem_release, devm_nvmem_match, nvmem);
776f1f50ecaSAndrey Smirnov }
777f1f50ecaSAndrey Smirnov EXPORT_SYMBOL(devm_nvmem_unregister);
778f1f50ecaSAndrey Smirnov 
77969aba794SSrinivas Kandagatla static struct nvmem_device *__nvmem_device_get(struct device_node *np,
780506157beSBartosz Golaszewski 					       const char *nvmem_name)
78169aba794SSrinivas Kandagatla {
78269aba794SSrinivas Kandagatla 	struct nvmem_device *nvmem = NULL;
78369aba794SSrinivas Kandagatla 
784c7235ee3SBartosz Golaszewski 	mutex_lock(&nvmem_mutex);
785506157beSBartosz Golaszewski 	nvmem = np ? of_nvmem_find(np) : nvmem_find(nvmem_name);
78669aba794SSrinivas Kandagatla 	mutex_unlock(&nvmem_mutex);
787c7235ee3SBartosz Golaszewski 	if (!nvmem)
788c7235ee3SBartosz Golaszewski 		return ERR_PTR(-EPROBE_DEFER);
78969aba794SSrinivas Kandagatla 
79069aba794SSrinivas Kandagatla 	if (!try_module_get(nvmem->owner)) {
79169aba794SSrinivas Kandagatla 		dev_err(&nvmem->dev,
79269aba794SSrinivas Kandagatla 			"could not increase module refcount for cell %s\n",
7935db652c9SBartosz Golaszewski 			nvmem_dev_name(nvmem));
79469aba794SSrinivas Kandagatla 
79569aba794SSrinivas Kandagatla 		return ERR_PTR(-EINVAL);
79669aba794SSrinivas Kandagatla 	}
79769aba794SSrinivas Kandagatla 
798c1de7f43SBartosz Golaszewski 	kref_get(&nvmem->refcnt);
799c1de7f43SBartosz Golaszewski 
80069aba794SSrinivas Kandagatla 	return nvmem;
80169aba794SSrinivas Kandagatla }
80269aba794SSrinivas Kandagatla 
80369aba794SSrinivas Kandagatla static void __nvmem_device_put(struct nvmem_device *nvmem)
80469aba794SSrinivas Kandagatla {
80569aba794SSrinivas Kandagatla 	module_put(nvmem->owner);
806c1de7f43SBartosz Golaszewski 	kref_put(&nvmem->refcnt, nvmem_device_release);
80769aba794SSrinivas Kandagatla }
80869aba794SSrinivas Kandagatla 
809e701c67cSMasahiro Yamada #if IS_ENABLED(CONFIG_OF)
810e2a5402eSSrinivas Kandagatla /**
811e2a5402eSSrinivas Kandagatla  * of_nvmem_device_get() - Get nvmem device from a given id
812e2a5402eSSrinivas Kandagatla  *
81329143268SVivek Gautam  * @np: Device tree node that uses the nvmem device.
814e2a5402eSSrinivas Kandagatla  * @id: nvmem name from nvmem-names property.
815e2a5402eSSrinivas Kandagatla  *
816e2a5402eSSrinivas Kandagatla  * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device
817e2a5402eSSrinivas Kandagatla  * on success.
818e2a5402eSSrinivas Kandagatla  */
819e2a5402eSSrinivas Kandagatla struct nvmem_device *of_nvmem_device_get(struct device_node *np, const char *id)
820e2a5402eSSrinivas Kandagatla {
821e2a5402eSSrinivas Kandagatla 
822e2a5402eSSrinivas Kandagatla 	struct device_node *nvmem_np;
823e2a5402eSSrinivas Kandagatla 	int index;
824e2a5402eSSrinivas Kandagatla 
825e2a5402eSSrinivas Kandagatla 	index = of_property_match_string(np, "nvmem-names", id);
826e2a5402eSSrinivas Kandagatla 
827e2a5402eSSrinivas Kandagatla 	nvmem_np = of_parse_phandle(np, "nvmem", index);
828e2a5402eSSrinivas Kandagatla 	if (!nvmem_np)
829e2a5402eSSrinivas Kandagatla 		return ERR_PTR(-EINVAL);
830e2a5402eSSrinivas Kandagatla 
831506157beSBartosz Golaszewski 	return __nvmem_device_get(nvmem_np, NULL);
832e2a5402eSSrinivas Kandagatla }
833e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_nvmem_device_get);
834e2a5402eSSrinivas Kandagatla #endif
835e2a5402eSSrinivas Kandagatla 
836e2a5402eSSrinivas Kandagatla /**
837e2a5402eSSrinivas Kandagatla  * nvmem_device_get() - Get nvmem device from a given id
838e2a5402eSSrinivas Kandagatla  *
83929143268SVivek Gautam  * @dev: Device that uses the nvmem device.
84029143268SVivek Gautam  * @dev_name: name of the requested nvmem device.
841e2a5402eSSrinivas Kandagatla  *
842e2a5402eSSrinivas Kandagatla  * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device
843e2a5402eSSrinivas Kandagatla  * on success.
844e2a5402eSSrinivas Kandagatla  */
845e2a5402eSSrinivas Kandagatla struct nvmem_device *nvmem_device_get(struct device *dev, const char *dev_name)
846e2a5402eSSrinivas Kandagatla {
847e2a5402eSSrinivas Kandagatla 	if (dev->of_node) { /* try dt first */
848e2a5402eSSrinivas Kandagatla 		struct nvmem_device *nvmem;
849e2a5402eSSrinivas Kandagatla 
850e2a5402eSSrinivas Kandagatla 		nvmem = of_nvmem_device_get(dev->of_node, dev_name);
851e2a5402eSSrinivas Kandagatla 
852e2a5402eSSrinivas Kandagatla 		if (!IS_ERR(nvmem) || PTR_ERR(nvmem) == -EPROBE_DEFER)
853e2a5402eSSrinivas Kandagatla 			return nvmem;
854e2a5402eSSrinivas Kandagatla 
855e2a5402eSSrinivas Kandagatla 	}
856e2a5402eSSrinivas Kandagatla 
857e2a5402eSSrinivas Kandagatla 	return nvmem_find(dev_name);
858e2a5402eSSrinivas Kandagatla }
859e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_get);
860e2a5402eSSrinivas Kandagatla 
861e2a5402eSSrinivas Kandagatla static int devm_nvmem_device_match(struct device *dev, void *res, void *data)
862e2a5402eSSrinivas Kandagatla {
863e2a5402eSSrinivas Kandagatla 	struct nvmem_device **nvmem = res;
864e2a5402eSSrinivas Kandagatla 
865e2a5402eSSrinivas Kandagatla 	if (WARN_ON(!nvmem || !*nvmem))
866e2a5402eSSrinivas Kandagatla 		return 0;
867e2a5402eSSrinivas Kandagatla 
868e2a5402eSSrinivas Kandagatla 	return *nvmem == data;
869e2a5402eSSrinivas Kandagatla }
870e2a5402eSSrinivas Kandagatla 
871e2a5402eSSrinivas Kandagatla static void devm_nvmem_device_release(struct device *dev, void *res)
872e2a5402eSSrinivas Kandagatla {
873e2a5402eSSrinivas Kandagatla 	nvmem_device_put(*(struct nvmem_device **)res);
874e2a5402eSSrinivas Kandagatla }
875e2a5402eSSrinivas Kandagatla 
876e2a5402eSSrinivas Kandagatla /**
877e2a5402eSSrinivas Kandagatla  * devm_nvmem_device_put() - put alredy got nvmem device
878e2a5402eSSrinivas Kandagatla  *
87929143268SVivek Gautam  * @dev: Device that uses the nvmem device.
880e2a5402eSSrinivas Kandagatla  * @nvmem: pointer to nvmem device allocated by devm_nvmem_cell_get(),
881e2a5402eSSrinivas Kandagatla  * that needs to be released.
882e2a5402eSSrinivas Kandagatla  */
883e2a5402eSSrinivas Kandagatla void devm_nvmem_device_put(struct device *dev, struct nvmem_device *nvmem)
884e2a5402eSSrinivas Kandagatla {
885e2a5402eSSrinivas Kandagatla 	int ret;
886e2a5402eSSrinivas Kandagatla 
887e2a5402eSSrinivas Kandagatla 	ret = devres_release(dev, devm_nvmem_device_release,
888e2a5402eSSrinivas Kandagatla 			     devm_nvmem_device_match, nvmem);
889e2a5402eSSrinivas Kandagatla 
890e2a5402eSSrinivas Kandagatla 	WARN_ON(ret);
891e2a5402eSSrinivas Kandagatla }
892e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_device_put);
893e2a5402eSSrinivas Kandagatla 
894e2a5402eSSrinivas Kandagatla /**
895e2a5402eSSrinivas Kandagatla  * nvmem_device_put() - put alredy got nvmem device
896e2a5402eSSrinivas Kandagatla  *
897e2a5402eSSrinivas Kandagatla  * @nvmem: pointer to nvmem device that needs to be released.
898e2a5402eSSrinivas Kandagatla  */
899e2a5402eSSrinivas Kandagatla void nvmem_device_put(struct nvmem_device *nvmem)
900e2a5402eSSrinivas Kandagatla {
901e2a5402eSSrinivas Kandagatla 	__nvmem_device_put(nvmem);
902e2a5402eSSrinivas Kandagatla }
903e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_put);
904e2a5402eSSrinivas Kandagatla 
905e2a5402eSSrinivas Kandagatla /**
906e2a5402eSSrinivas Kandagatla  * devm_nvmem_device_get() - Get nvmem cell of device form a given id
907e2a5402eSSrinivas Kandagatla  *
90829143268SVivek Gautam  * @dev: Device that requests the nvmem device.
90929143268SVivek Gautam  * @id: name id for the requested nvmem device.
910e2a5402eSSrinivas Kandagatla  *
911e2a5402eSSrinivas Kandagatla  * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_cell
912e2a5402eSSrinivas Kandagatla  * on success.  The nvmem_cell will be freed by the automatically once the
913e2a5402eSSrinivas Kandagatla  * device is freed.
914e2a5402eSSrinivas Kandagatla  */
915e2a5402eSSrinivas Kandagatla struct nvmem_device *devm_nvmem_device_get(struct device *dev, const char *id)
916e2a5402eSSrinivas Kandagatla {
917e2a5402eSSrinivas Kandagatla 	struct nvmem_device **ptr, *nvmem;
918e2a5402eSSrinivas Kandagatla 
919e2a5402eSSrinivas Kandagatla 	ptr = devres_alloc(devm_nvmem_device_release, sizeof(*ptr), GFP_KERNEL);
920e2a5402eSSrinivas Kandagatla 	if (!ptr)
921e2a5402eSSrinivas Kandagatla 		return ERR_PTR(-ENOMEM);
922e2a5402eSSrinivas Kandagatla 
923e2a5402eSSrinivas Kandagatla 	nvmem = nvmem_device_get(dev, id);
924e2a5402eSSrinivas Kandagatla 	if (!IS_ERR(nvmem)) {
925e2a5402eSSrinivas Kandagatla 		*ptr = nvmem;
926e2a5402eSSrinivas Kandagatla 		devres_add(dev, ptr);
927e2a5402eSSrinivas Kandagatla 	} else {
928e2a5402eSSrinivas Kandagatla 		devres_free(ptr);
929e2a5402eSSrinivas Kandagatla 	}
930e2a5402eSSrinivas Kandagatla 
931e2a5402eSSrinivas Kandagatla 	return nvmem;
932e2a5402eSSrinivas Kandagatla }
933e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_device_get);
934e2a5402eSSrinivas Kandagatla 
935506157beSBartosz Golaszewski static struct nvmem_cell *
936506157beSBartosz Golaszewski nvmem_cell_get_from_lookup(struct device *dev, const char *con_id)
93769aba794SSrinivas Kandagatla {
938506157beSBartosz Golaszewski 	struct nvmem_cell *cell = ERR_PTR(-ENOENT);
939506157beSBartosz Golaszewski 	struct nvmem_cell_lookup *lookup;
94069aba794SSrinivas Kandagatla 	struct nvmem_device *nvmem;
941506157beSBartosz Golaszewski 	const char *dev_id;
94269aba794SSrinivas Kandagatla 
943506157beSBartosz Golaszewski 	if (!dev)
944506157beSBartosz Golaszewski 		return ERR_PTR(-EINVAL);
94569aba794SSrinivas Kandagatla 
946506157beSBartosz Golaszewski 	dev_id = dev_name(dev);
947506157beSBartosz Golaszewski 
948506157beSBartosz Golaszewski 	mutex_lock(&nvmem_lookup_mutex);
949506157beSBartosz Golaszewski 
950506157beSBartosz Golaszewski 	list_for_each_entry(lookup, &nvmem_lookup_list, node) {
951506157beSBartosz Golaszewski 		if ((strcmp(lookup->dev_id, dev_id) == 0) &&
952506157beSBartosz Golaszewski 		    (strcmp(lookup->con_id, con_id) == 0)) {
953506157beSBartosz Golaszewski 			/* This is the right entry. */
954506157beSBartosz Golaszewski 			nvmem = __nvmem_device_get(NULL, lookup->nvmem_name);
955506157beSBartosz Golaszewski 			if (!nvmem) {
956506157beSBartosz Golaszewski 				/* Provider may not be registered yet. */
957506157beSBartosz Golaszewski 				cell = ERR_PTR(-EPROBE_DEFER);
958506157beSBartosz Golaszewski 				goto out;
959506157beSBartosz Golaszewski 			}
960506157beSBartosz Golaszewski 
961506157beSBartosz Golaszewski 			cell = nvmem_find_cell_by_name(nvmem,
962506157beSBartosz Golaszewski 						       lookup->cell_name);
963506157beSBartosz Golaszewski 			if (!cell) {
964506157beSBartosz Golaszewski 				__nvmem_device_put(nvmem);
965506157beSBartosz Golaszewski 				goto out;
966506157beSBartosz Golaszewski 			}
967506157beSBartosz Golaszewski 		}
968506157beSBartosz Golaszewski 	}
969506157beSBartosz Golaszewski 
970506157beSBartosz Golaszewski out:
971506157beSBartosz Golaszewski 	mutex_unlock(&nvmem_lookup_mutex);
97269aba794SSrinivas Kandagatla 	return cell;
97369aba794SSrinivas Kandagatla }
97469aba794SSrinivas Kandagatla 
975e701c67cSMasahiro Yamada #if IS_ENABLED(CONFIG_OF)
97669aba794SSrinivas Kandagatla /**
97769aba794SSrinivas Kandagatla  * of_nvmem_cell_get() - Get a nvmem cell from given device node and cell id
97869aba794SSrinivas Kandagatla  *
97929143268SVivek Gautam  * @np: Device tree node that uses the nvmem cell.
980*165589f0SBartosz Golaszewski  * @id: nvmem cell name from nvmem-cell-names property, or NULL
981fd0c478cSVivek Gautam  *      for the cell at index 0 (the lone cell with no accompanying
982fd0c478cSVivek Gautam  *      nvmem-cell-names property).
98369aba794SSrinivas Kandagatla  *
98469aba794SSrinivas Kandagatla  * Return: Will be an ERR_PTR() on error or a valid pointer
98569aba794SSrinivas Kandagatla  * to a struct nvmem_cell.  The nvmem_cell will be freed by the
98669aba794SSrinivas Kandagatla  * nvmem_cell_put().
98769aba794SSrinivas Kandagatla  */
988*165589f0SBartosz Golaszewski struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *id)
98969aba794SSrinivas Kandagatla {
99069aba794SSrinivas Kandagatla 	struct device_node *cell_np, *nvmem_np;
99169aba794SSrinivas Kandagatla 	struct nvmem_device *nvmem;
992e888d445SBartosz Golaszewski 	struct nvmem_cell *cell;
993fd0c478cSVivek Gautam 	int index = 0;
99469aba794SSrinivas Kandagatla 
995fd0c478cSVivek Gautam 	/* if cell name exists, find index to the name */
996*165589f0SBartosz Golaszewski 	if (id)
997*165589f0SBartosz Golaszewski 		index = of_property_match_string(np, "nvmem-cell-names", id);
99869aba794SSrinivas Kandagatla 
99969aba794SSrinivas Kandagatla 	cell_np = of_parse_phandle(np, "nvmem-cells", index);
100069aba794SSrinivas Kandagatla 	if (!cell_np)
100169aba794SSrinivas Kandagatla 		return ERR_PTR(-EINVAL);
100269aba794SSrinivas Kandagatla 
100369aba794SSrinivas Kandagatla 	nvmem_np = of_get_next_parent(cell_np);
100469aba794SSrinivas Kandagatla 	if (!nvmem_np)
100569aba794SSrinivas Kandagatla 		return ERR_PTR(-EINVAL);
100669aba794SSrinivas Kandagatla 
1007506157beSBartosz Golaszewski 	nvmem = __nvmem_device_get(nvmem_np, NULL);
1008aad8d097SMasahiro Yamada 	of_node_put(nvmem_np);
100969aba794SSrinivas Kandagatla 	if (IS_ERR(nvmem))
101069aba794SSrinivas Kandagatla 		return ERR_CAST(nvmem);
101169aba794SSrinivas Kandagatla 
1012e888d445SBartosz Golaszewski 	cell = nvmem_find_cell_by_index(nvmem, index);
101369aba794SSrinivas Kandagatla 	if (!cell) {
1014e888d445SBartosz Golaszewski 		__nvmem_device_put(nvmem);
1015e888d445SBartosz Golaszewski 		return ERR_PTR(-ENOENT);
101669aba794SSrinivas Kandagatla 	}
101769aba794SSrinivas Kandagatla 
101869aba794SSrinivas Kandagatla 	return cell;
101969aba794SSrinivas Kandagatla }
102069aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_nvmem_cell_get);
102169aba794SSrinivas Kandagatla #endif
102269aba794SSrinivas Kandagatla 
102369aba794SSrinivas Kandagatla /**
102469aba794SSrinivas Kandagatla  * nvmem_cell_get() - Get nvmem cell of device form a given cell name
102569aba794SSrinivas Kandagatla  *
102629143268SVivek Gautam  * @dev: Device that requests the nvmem cell.
1027*165589f0SBartosz Golaszewski  * @id: nvmem cell name to get (this corresponds with the name from the
1028*165589f0SBartosz Golaszewski  *      nvmem-cell-names property for DT systems and with the con_id from
1029*165589f0SBartosz Golaszewski  *      the lookup entry for non-DT systems).
103069aba794SSrinivas Kandagatla  *
103169aba794SSrinivas Kandagatla  * Return: Will be an ERR_PTR() on error or a valid pointer
103269aba794SSrinivas Kandagatla  * to a struct nvmem_cell.  The nvmem_cell will be freed by the
103369aba794SSrinivas Kandagatla  * nvmem_cell_put().
103469aba794SSrinivas Kandagatla  */
1035*165589f0SBartosz Golaszewski struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *id)
103669aba794SSrinivas Kandagatla {
103769aba794SSrinivas Kandagatla 	struct nvmem_cell *cell;
103869aba794SSrinivas Kandagatla 
103969aba794SSrinivas Kandagatla 	if (dev->of_node) { /* try dt first */
1040*165589f0SBartosz Golaszewski 		cell = of_nvmem_cell_get(dev->of_node, id);
104169aba794SSrinivas Kandagatla 		if (!IS_ERR(cell) || PTR_ERR(cell) == -EPROBE_DEFER)
104269aba794SSrinivas Kandagatla 			return cell;
104369aba794SSrinivas Kandagatla 	}
104469aba794SSrinivas Kandagatla 
1045*165589f0SBartosz Golaszewski 	/* NULL cell id only allowed for device tree; invalid otherwise */
1046*165589f0SBartosz Golaszewski 	if (!id)
104787ed1405SDouglas Anderson 		return ERR_PTR(-EINVAL);
104887ed1405SDouglas Anderson 
1049*165589f0SBartosz Golaszewski 	return nvmem_cell_get_from_lookup(dev, id);
105069aba794SSrinivas Kandagatla }
105169aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_get);
105269aba794SSrinivas Kandagatla 
105369aba794SSrinivas Kandagatla static void devm_nvmem_cell_release(struct device *dev, void *res)
105469aba794SSrinivas Kandagatla {
105569aba794SSrinivas Kandagatla 	nvmem_cell_put(*(struct nvmem_cell **)res);
105669aba794SSrinivas Kandagatla }
105769aba794SSrinivas Kandagatla 
105869aba794SSrinivas Kandagatla /**
105969aba794SSrinivas Kandagatla  * devm_nvmem_cell_get() - Get nvmem cell of device form a given id
106069aba794SSrinivas Kandagatla  *
106129143268SVivek Gautam  * @dev: Device that requests the nvmem cell.
106229143268SVivek Gautam  * @id: nvmem cell name id to get.
106369aba794SSrinivas Kandagatla  *
106469aba794SSrinivas Kandagatla  * Return: Will be an ERR_PTR() on error or a valid pointer
106569aba794SSrinivas Kandagatla  * to a struct nvmem_cell.  The nvmem_cell will be freed by the
106669aba794SSrinivas Kandagatla  * automatically once the device is freed.
106769aba794SSrinivas Kandagatla  */
106869aba794SSrinivas Kandagatla struct nvmem_cell *devm_nvmem_cell_get(struct device *dev, const char *id)
106969aba794SSrinivas Kandagatla {
107069aba794SSrinivas Kandagatla 	struct nvmem_cell **ptr, *cell;
107169aba794SSrinivas Kandagatla 
107269aba794SSrinivas Kandagatla 	ptr = devres_alloc(devm_nvmem_cell_release, sizeof(*ptr), GFP_KERNEL);
107369aba794SSrinivas Kandagatla 	if (!ptr)
107469aba794SSrinivas Kandagatla 		return ERR_PTR(-ENOMEM);
107569aba794SSrinivas Kandagatla 
107669aba794SSrinivas Kandagatla 	cell = nvmem_cell_get(dev, id);
107769aba794SSrinivas Kandagatla 	if (!IS_ERR(cell)) {
107869aba794SSrinivas Kandagatla 		*ptr = cell;
107969aba794SSrinivas Kandagatla 		devres_add(dev, ptr);
108069aba794SSrinivas Kandagatla 	} else {
108169aba794SSrinivas Kandagatla 		devres_free(ptr);
108269aba794SSrinivas Kandagatla 	}
108369aba794SSrinivas Kandagatla 
108469aba794SSrinivas Kandagatla 	return cell;
108569aba794SSrinivas Kandagatla }
108669aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_cell_get);
108769aba794SSrinivas Kandagatla 
108869aba794SSrinivas Kandagatla static int devm_nvmem_cell_match(struct device *dev, void *res, void *data)
108969aba794SSrinivas Kandagatla {
109069aba794SSrinivas Kandagatla 	struct nvmem_cell **c = res;
109169aba794SSrinivas Kandagatla 
109269aba794SSrinivas Kandagatla 	if (WARN_ON(!c || !*c))
109369aba794SSrinivas Kandagatla 		return 0;
109469aba794SSrinivas Kandagatla 
109569aba794SSrinivas Kandagatla 	return *c == data;
109669aba794SSrinivas Kandagatla }
109769aba794SSrinivas Kandagatla 
109869aba794SSrinivas Kandagatla /**
109969aba794SSrinivas Kandagatla  * devm_nvmem_cell_put() - Release previously allocated nvmem cell
110069aba794SSrinivas Kandagatla  * from devm_nvmem_cell_get.
110169aba794SSrinivas Kandagatla  *
110229143268SVivek Gautam  * @dev: Device that requests the nvmem cell.
110329143268SVivek Gautam  * @cell: Previously allocated nvmem cell by devm_nvmem_cell_get().
110469aba794SSrinivas Kandagatla  */
110569aba794SSrinivas Kandagatla void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell)
110669aba794SSrinivas Kandagatla {
110769aba794SSrinivas Kandagatla 	int ret;
110869aba794SSrinivas Kandagatla 
110969aba794SSrinivas Kandagatla 	ret = devres_release(dev, devm_nvmem_cell_release,
111069aba794SSrinivas Kandagatla 				devm_nvmem_cell_match, cell);
111169aba794SSrinivas Kandagatla 
111269aba794SSrinivas Kandagatla 	WARN_ON(ret);
111369aba794SSrinivas Kandagatla }
111469aba794SSrinivas Kandagatla EXPORT_SYMBOL(devm_nvmem_cell_put);
111569aba794SSrinivas Kandagatla 
111669aba794SSrinivas Kandagatla /**
111769aba794SSrinivas Kandagatla  * nvmem_cell_put() - Release previously allocated nvmem cell.
111869aba794SSrinivas Kandagatla  *
111929143268SVivek Gautam  * @cell: Previously allocated nvmem cell by nvmem_cell_get().
112069aba794SSrinivas Kandagatla  */
112169aba794SSrinivas Kandagatla void nvmem_cell_put(struct nvmem_cell *cell)
112269aba794SSrinivas Kandagatla {
112369aba794SSrinivas Kandagatla 	struct nvmem_device *nvmem = cell->nvmem;
112469aba794SSrinivas Kandagatla 
112569aba794SSrinivas Kandagatla 	__nvmem_device_put(nvmem);
112669aba794SSrinivas Kandagatla }
112769aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_put);
112869aba794SSrinivas Kandagatla 
1129f7c04f16SMasahiro Yamada static void nvmem_shift_read_buffer_in_place(struct nvmem_cell *cell, void *buf)
113069aba794SSrinivas Kandagatla {
113169aba794SSrinivas Kandagatla 	u8 *p, *b;
113269aba794SSrinivas Kandagatla 	int i, bit_offset = cell->bit_offset;
113369aba794SSrinivas Kandagatla 
113469aba794SSrinivas Kandagatla 	p = b = buf;
113569aba794SSrinivas Kandagatla 	if (bit_offset) {
113669aba794SSrinivas Kandagatla 		/* First shift */
113769aba794SSrinivas Kandagatla 		*b++ >>= bit_offset;
113869aba794SSrinivas Kandagatla 
113969aba794SSrinivas Kandagatla 		/* setup rest of the bytes if any */
114069aba794SSrinivas Kandagatla 		for (i = 1; i < cell->bytes; i++) {
114169aba794SSrinivas Kandagatla 			/* Get bits from next byte and shift them towards msb */
114269aba794SSrinivas Kandagatla 			*p |= *b << (BITS_PER_BYTE - bit_offset);
114369aba794SSrinivas Kandagatla 
114469aba794SSrinivas Kandagatla 			p = b;
114569aba794SSrinivas Kandagatla 			*b++ >>= bit_offset;
114669aba794SSrinivas Kandagatla 		}
114769aba794SSrinivas Kandagatla 
114869aba794SSrinivas Kandagatla 		/* result fits in less bytes */
114969aba794SSrinivas Kandagatla 		if (cell->bytes != DIV_ROUND_UP(cell->nbits, BITS_PER_BYTE))
115069aba794SSrinivas Kandagatla 			*p-- = 0;
115169aba794SSrinivas Kandagatla 	}
115269aba794SSrinivas Kandagatla 	/* clear msb bits if any leftover in the last byte */
115369aba794SSrinivas Kandagatla 	*p &= GENMASK((cell->nbits%BITS_PER_BYTE) - 1, 0);
115469aba794SSrinivas Kandagatla }
115569aba794SSrinivas Kandagatla 
115669aba794SSrinivas Kandagatla static int __nvmem_cell_read(struct nvmem_device *nvmem,
115769aba794SSrinivas Kandagatla 		      struct nvmem_cell *cell,
115869aba794SSrinivas Kandagatla 		      void *buf, size_t *len)
115969aba794SSrinivas Kandagatla {
116069aba794SSrinivas Kandagatla 	int rc;
116169aba794SSrinivas Kandagatla 
1162795ddd18SSrinivas Kandagatla 	rc = nvmem_reg_read(nvmem, cell->offset, buf, cell->bytes);
116369aba794SSrinivas Kandagatla 
1164287980e4SArnd Bergmann 	if (rc)
116569aba794SSrinivas Kandagatla 		return rc;
116669aba794SSrinivas Kandagatla 
116769aba794SSrinivas Kandagatla 	/* shift bits in-place */
1168cbf854abSAxel Lin 	if (cell->bit_offset || cell->nbits)
116969aba794SSrinivas Kandagatla 		nvmem_shift_read_buffer_in_place(cell, buf);
117069aba794SSrinivas Kandagatla 
11713b4a6877SVivek Gautam 	if (len)
117269aba794SSrinivas Kandagatla 		*len = cell->bytes;
117369aba794SSrinivas Kandagatla 
117469aba794SSrinivas Kandagatla 	return 0;
117569aba794SSrinivas Kandagatla }
117669aba794SSrinivas Kandagatla 
117769aba794SSrinivas Kandagatla /**
117869aba794SSrinivas Kandagatla  * nvmem_cell_read() - Read a given nvmem cell
117969aba794SSrinivas Kandagatla  *
118069aba794SSrinivas Kandagatla  * @cell: nvmem cell to be read.
11813b4a6877SVivek Gautam  * @len: pointer to length of cell which will be populated on successful read;
11823b4a6877SVivek Gautam  *	 can be NULL.
118369aba794SSrinivas Kandagatla  *
1184b577fafcSBrian Norris  * Return: ERR_PTR() on error or a valid pointer to a buffer on success. The
1185b577fafcSBrian Norris  * buffer should be freed by the consumer with a kfree().
118669aba794SSrinivas Kandagatla  */
118769aba794SSrinivas Kandagatla void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len)
118869aba794SSrinivas Kandagatla {
118969aba794SSrinivas Kandagatla 	struct nvmem_device *nvmem = cell->nvmem;
119069aba794SSrinivas Kandagatla 	u8 *buf;
119169aba794SSrinivas Kandagatla 	int rc;
119269aba794SSrinivas Kandagatla 
1193795ddd18SSrinivas Kandagatla 	if (!nvmem)
119469aba794SSrinivas Kandagatla 		return ERR_PTR(-EINVAL);
119569aba794SSrinivas Kandagatla 
119669aba794SSrinivas Kandagatla 	buf = kzalloc(cell->bytes, GFP_KERNEL);
119769aba794SSrinivas Kandagatla 	if (!buf)
119869aba794SSrinivas Kandagatla 		return ERR_PTR(-ENOMEM);
119969aba794SSrinivas Kandagatla 
120069aba794SSrinivas Kandagatla 	rc = __nvmem_cell_read(nvmem, cell, buf, len);
1201287980e4SArnd Bergmann 	if (rc) {
120269aba794SSrinivas Kandagatla 		kfree(buf);
120369aba794SSrinivas Kandagatla 		return ERR_PTR(rc);
120469aba794SSrinivas Kandagatla 	}
120569aba794SSrinivas Kandagatla 
120669aba794SSrinivas Kandagatla 	return buf;
120769aba794SSrinivas Kandagatla }
120869aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_read);
120969aba794SSrinivas Kandagatla 
1210f7c04f16SMasahiro Yamada static void *nvmem_cell_prepare_write_buffer(struct nvmem_cell *cell,
121169aba794SSrinivas Kandagatla 					     u8 *_buf, int len)
121269aba794SSrinivas Kandagatla {
121369aba794SSrinivas Kandagatla 	struct nvmem_device *nvmem = cell->nvmem;
121469aba794SSrinivas Kandagatla 	int i, rc, nbits, bit_offset = cell->bit_offset;
121569aba794SSrinivas Kandagatla 	u8 v, *p, *buf, *b, pbyte, pbits;
121669aba794SSrinivas Kandagatla 
121769aba794SSrinivas Kandagatla 	nbits = cell->nbits;
121869aba794SSrinivas Kandagatla 	buf = kzalloc(cell->bytes, GFP_KERNEL);
121969aba794SSrinivas Kandagatla 	if (!buf)
122069aba794SSrinivas Kandagatla 		return ERR_PTR(-ENOMEM);
122169aba794SSrinivas Kandagatla 
122269aba794SSrinivas Kandagatla 	memcpy(buf, _buf, len);
122369aba794SSrinivas Kandagatla 	p = b = buf;
122469aba794SSrinivas Kandagatla 
122569aba794SSrinivas Kandagatla 	if (bit_offset) {
122669aba794SSrinivas Kandagatla 		pbyte = *b;
122769aba794SSrinivas Kandagatla 		*b <<= bit_offset;
122869aba794SSrinivas Kandagatla 
122969aba794SSrinivas Kandagatla 		/* setup the first byte with lsb bits from nvmem */
1230795ddd18SSrinivas Kandagatla 		rc = nvmem_reg_read(nvmem, cell->offset, &v, 1);
123150808bfcSMathieu Malaterre 		if (rc)
123250808bfcSMathieu Malaterre 			goto err;
123369aba794SSrinivas Kandagatla 		*b++ |= GENMASK(bit_offset - 1, 0) & v;
123469aba794SSrinivas Kandagatla 
123569aba794SSrinivas Kandagatla 		/* setup rest of the byte if any */
123669aba794SSrinivas Kandagatla 		for (i = 1; i < cell->bytes; i++) {
123769aba794SSrinivas Kandagatla 			/* Get last byte bits and shift them towards lsb */
123869aba794SSrinivas Kandagatla 			pbits = pbyte >> (BITS_PER_BYTE - 1 - bit_offset);
123969aba794SSrinivas Kandagatla 			pbyte = *b;
124069aba794SSrinivas Kandagatla 			p = b;
124169aba794SSrinivas Kandagatla 			*b <<= bit_offset;
124269aba794SSrinivas Kandagatla 			*b++ |= pbits;
124369aba794SSrinivas Kandagatla 		}
124469aba794SSrinivas Kandagatla 	}
124569aba794SSrinivas Kandagatla 
124669aba794SSrinivas Kandagatla 	/* if it's not end on byte boundary */
124769aba794SSrinivas Kandagatla 	if ((nbits + bit_offset) % BITS_PER_BYTE) {
124869aba794SSrinivas Kandagatla 		/* setup the last byte with msb bits from nvmem */
1249795ddd18SSrinivas Kandagatla 		rc = nvmem_reg_read(nvmem,
125069aba794SSrinivas Kandagatla 				    cell->offset + cell->bytes - 1, &v, 1);
125150808bfcSMathieu Malaterre 		if (rc)
125250808bfcSMathieu Malaterre 			goto err;
125369aba794SSrinivas Kandagatla 		*p |= GENMASK(7, (nbits + bit_offset) % BITS_PER_BYTE) & v;
125469aba794SSrinivas Kandagatla 
125569aba794SSrinivas Kandagatla 	}
125669aba794SSrinivas Kandagatla 
125769aba794SSrinivas Kandagatla 	return buf;
125850808bfcSMathieu Malaterre err:
125950808bfcSMathieu Malaterre 	kfree(buf);
126050808bfcSMathieu Malaterre 	return ERR_PTR(rc);
126169aba794SSrinivas Kandagatla }
126269aba794SSrinivas Kandagatla 
126369aba794SSrinivas Kandagatla /**
126469aba794SSrinivas Kandagatla  * nvmem_cell_write() - Write to a given nvmem cell
126569aba794SSrinivas Kandagatla  *
126669aba794SSrinivas Kandagatla  * @cell: nvmem cell to be written.
126769aba794SSrinivas Kandagatla  * @buf: Buffer to be written.
126869aba794SSrinivas Kandagatla  * @len: length of buffer to be written to nvmem cell.
126969aba794SSrinivas Kandagatla  *
127069aba794SSrinivas Kandagatla  * Return: length of bytes written or negative on failure.
127169aba794SSrinivas Kandagatla  */
127269aba794SSrinivas Kandagatla int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len)
127369aba794SSrinivas Kandagatla {
127469aba794SSrinivas Kandagatla 	struct nvmem_device *nvmem = cell->nvmem;
127569aba794SSrinivas Kandagatla 	int rc;
127669aba794SSrinivas Kandagatla 
1277795ddd18SSrinivas Kandagatla 	if (!nvmem || nvmem->read_only ||
127869aba794SSrinivas Kandagatla 	    (cell->bit_offset == 0 && len != cell->bytes))
127969aba794SSrinivas Kandagatla 		return -EINVAL;
128069aba794SSrinivas Kandagatla 
128169aba794SSrinivas Kandagatla 	if (cell->bit_offset || cell->nbits) {
128269aba794SSrinivas Kandagatla 		buf = nvmem_cell_prepare_write_buffer(cell, buf, len);
128369aba794SSrinivas Kandagatla 		if (IS_ERR(buf))
128469aba794SSrinivas Kandagatla 			return PTR_ERR(buf);
128569aba794SSrinivas Kandagatla 	}
128669aba794SSrinivas Kandagatla 
1287795ddd18SSrinivas Kandagatla 	rc = nvmem_reg_write(nvmem, cell->offset, buf, cell->bytes);
128869aba794SSrinivas Kandagatla 
128969aba794SSrinivas Kandagatla 	/* free the tmp buffer */
1290ace22170SAxel Lin 	if (cell->bit_offset || cell->nbits)
129169aba794SSrinivas Kandagatla 		kfree(buf);
129269aba794SSrinivas Kandagatla 
1293287980e4SArnd Bergmann 	if (rc)
129469aba794SSrinivas Kandagatla 		return rc;
129569aba794SSrinivas Kandagatla 
129669aba794SSrinivas Kandagatla 	return len;
129769aba794SSrinivas Kandagatla }
129869aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_write);
129969aba794SSrinivas Kandagatla 
1300e2a5402eSSrinivas Kandagatla /**
1301d026d70aSLeonard Crestez  * nvmem_cell_read_u32() - Read a cell value as an u32
1302d026d70aSLeonard Crestez  *
1303d026d70aSLeonard Crestez  * @dev: Device that requests the nvmem cell.
1304d026d70aSLeonard Crestez  * @cell_id: Name of nvmem cell to read.
1305d026d70aSLeonard Crestez  * @val: pointer to output value.
1306d026d70aSLeonard Crestez  *
1307d026d70aSLeonard Crestez  * Return: 0 on success or negative errno.
1308d026d70aSLeonard Crestez  */
1309d026d70aSLeonard Crestez int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val)
1310d026d70aSLeonard Crestez {
1311d026d70aSLeonard Crestez 	struct nvmem_cell *cell;
1312d026d70aSLeonard Crestez 	void *buf;
1313d026d70aSLeonard Crestez 	size_t len;
1314d026d70aSLeonard Crestez 
1315d026d70aSLeonard Crestez 	cell = nvmem_cell_get(dev, cell_id);
1316d026d70aSLeonard Crestez 	if (IS_ERR(cell))
1317d026d70aSLeonard Crestez 		return PTR_ERR(cell);
1318d026d70aSLeonard Crestez 
1319d026d70aSLeonard Crestez 	buf = nvmem_cell_read(cell, &len);
1320d026d70aSLeonard Crestez 	if (IS_ERR(buf)) {
1321d026d70aSLeonard Crestez 		nvmem_cell_put(cell);
1322d026d70aSLeonard Crestez 		return PTR_ERR(buf);
1323d026d70aSLeonard Crestez 	}
1324d026d70aSLeonard Crestez 	if (len != sizeof(*val)) {
1325d026d70aSLeonard Crestez 		kfree(buf);
1326d026d70aSLeonard Crestez 		nvmem_cell_put(cell);
1327d026d70aSLeonard Crestez 		return -EINVAL;
1328d026d70aSLeonard Crestez 	}
1329d026d70aSLeonard Crestez 	memcpy(val, buf, sizeof(*val));
1330d026d70aSLeonard Crestez 
1331d026d70aSLeonard Crestez 	kfree(buf);
1332d026d70aSLeonard Crestez 	nvmem_cell_put(cell);
1333d026d70aSLeonard Crestez 	return 0;
1334d026d70aSLeonard Crestez }
1335d026d70aSLeonard Crestez EXPORT_SYMBOL_GPL(nvmem_cell_read_u32);
1336d026d70aSLeonard Crestez 
1337d026d70aSLeonard Crestez /**
1338e2a5402eSSrinivas Kandagatla  * nvmem_device_cell_read() - Read a given nvmem device and cell
1339e2a5402eSSrinivas Kandagatla  *
1340e2a5402eSSrinivas Kandagatla  * @nvmem: nvmem device to read from.
1341e2a5402eSSrinivas Kandagatla  * @info: nvmem cell info to be read.
1342e2a5402eSSrinivas Kandagatla  * @buf: buffer pointer which will be populated on successful read.
1343e2a5402eSSrinivas Kandagatla  *
1344e2a5402eSSrinivas Kandagatla  * Return: length of successful bytes read on success and negative
1345e2a5402eSSrinivas Kandagatla  * error code on error.
1346e2a5402eSSrinivas Kandagatla  */
1347e2a5402eSSrinivas Kandagatla ssize_t nvmem_device_cell_read(struct nvmem_device *nvmem,
1348e2a5402eSSrinivas Kandagatla 			   struct nvmem_cell_info *info, void *buf)
1349e2a5402eSSrinivas Kandagatla {
1350e2a5402eSSrinivas Kandagatla 	struct nvmem_cell cell;
1351e2a5402eSSrinivas Kandagatla 	int rc;
1352e2a5402eSSrinivas Kandagatla 	ssize_t len;
1353e2a5402eSSrinivas Kandagatla 
1354795ddd18SSrinivas Kandagatla 	if (!nvmem)
1355e2a5402eSSrinivas Kandagatla 		return -EINVAL;
1356e2a5402eSSrinivas Kandagatla 
1357e2a5402eSSrinivas Kandagatla 	rc = nvmem_cell_info_to_nvmem_cell(nvmem, info, &cell);
1358287980e4SArnd Bergmann 	if (rc)
1359e2a5402eSSrinivas Kandagatla 		return rc;
1360e2a5402eSSrinivas Kandagatla 
1361e2a5402eSSrinivas Kandagatla 	rc = __nvmem_cell_read(nvmem, &cell, buf, &len);
1362287980e4SArnd Bergmann 	if (rc)
1363e2a5402eSSrinivas Kandagatla 		return rc;
1364e2a5402eSSrinivas Kandagatla 
1365e2a5402eSSrinivas Kandagatla 	return len;
1366e2a5402eSSrinivas Kandagatla }
1367e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_cell_read);
1368e2a5402eSSrinivas Kandagatla 
1369e2a5402eSSrinivas Kandagatla /**
1370e2a5402eSSrinivas Kandagatla  * nvmem_device_cell_write() - Write cell to a given nvmem device
1371e2a5402eSSrinivas Kandagatla  *
1372e2a5402eSSrinivas Kandagatla  * @nvmem: nvmem device to be written to.
137329143268SVivek Gautam  * @info: nvmem cell info to be written.
1374e2a5402eSSrinivas Kandagatla  * @buf: buffer to be written to cell.
1375e2a5402eSSrinivas Kandagatla  *
1376e2a5402eSSrinivas Kandagatla  * Return: length of bytes written or negative error code on failure.
1377e2a5402eSSrinivas Kandagatla  * */
1378e2a5402eSSrinivas Kandagatla int nvmem_device_cell_write(struct nvmem_device *nvmem,
1379e2a5402eSSrinivas Kandagatla 			    struct nvmem_cell_info *info, void *buf)
1380e2a5402eSSrinivas Kandagatla {
1381e2a5402eSSrinivas Kandagatla 	struct nvmem_cell cell;
1382e2a5402eSSrinivas Kandagatla 	int rc;
1383e2a5402eSSrinivas Kandagatla 
1384795ddd18SSrinivas Kandagatla 	if (!nvmem)
1385e2a5402eSSrinivas Kandagatla 		return -EINVAL;
1386e2a5402eSSrinivas Kandagatla 
1387e2a5402eSSrinivas Kandagatla 	rc = nvmem_cell_info_to_nvmem_cell(nvmem, info, &cell);
1388287980e4SArnd Bergmann 	if (rc)
1389e2a5402eSSrinivas Kandagatla 		return rc;
1390e2a5402eSSrinivas Kandagatla 
1391e2a5402eSSrinivas Kandagatla 	return nvmem_cell_write(&cell, buf, cell.bytes);
1392e2a5402eSSrinivas Kandagatla }
1393e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_cell_write);
1394e2a5402eSSrinivas Kandagatla 
1395e2a5402eSSrinivas Kandagatla /**
1396e2a5402eSSrinivas Kandagatla  * nvmem_device_read() - Read from a given nvmem device
1397e2a5402eSSrinivas Kandagatla  *
1398e2a5402eSSrinivas Kandagatla  * @nvmem: nvmem device to read from.
1399e2a5402eSSrinivas Kandagatla  * @offset: offset in nvmem device.
1400e2a5402eSSrinivas Kandagatla  * @bytes: number of bytes to read.
1401e2a5402eSSrinivas Kandagatla  * @buf: buffer pointer which will be populated on successful read.
1402e2a5402eSSrinivas Kandagatla  *
1403e2a5402eSSrinivas Kandagatla  * Return: length of successful bytes read on success and negative
1404e2a5402eSSrinivas Kandagatla  * error code on error.
1405e2a5402eSSrinivas Kandagatla  */
1406e2a5402eSSrinivas Kandagatla int nvmem_device_read(struct nvmem_device *nvmem,
1407e2a5402eSSrinivas Kandagatla 		      unsigned int offset,
1408e2a5402eSSrinivas Kandagatla 		      size_t bytes, void *buf)
1409e2a5402eSSrinivas Kandagatla {
1410e2a5402eSSrinivas Kandagatla 	int rc;
1411e2a5402eSSrinivas Kandagatla 
1412795ddd18SSrinivas Kandagatla 	if (!nvmem)
1413e2a5402eSSrinivas Kandagatla 		return -EINVAL;
1414e2a5402eSSrinivas Kandagatla 
1415795ddd18SSrinivas Kandagatla 	rc = nvmem_reg_read(nvmem, offset, buf, bytes);
1416e2a5402eSSrinivas Kandagatla 
1417287980e4SArnd Bergmann 	if (rc)
1418e2a5402eSSrinivas Kandagatla 		return rc;
1419e2a5402eSSrinivas Kandagatla 
1420e2a5402eSSrinivas Kandagatla 	return bytes;
1421e2a5402eSSrinivas Kandagatla }
1422e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_read);
1423e2a5402eSSrinivas Kandagatla 
1424e2a5402eSSrinivas Kandagatla /**
1425e2a5402eSSrinivas Kandagatla  * nvmem_device_write() - Write cell to a given nvmem device
1426e2a5402eSSrinivas Kandagatla  *
1427e2a5402eSSrinivas Kandagatla  * @nvmem: nvmem device to be written to.
1428e2a5402eSSrinivas Kandagatla  * @offset: offset in nvmem device.
1429e2a5402eSSrinivas Kandagatla  * @bytes: number of bytes to write.
1430e2a5402eSSrinivas Kandagatla  * @buf: buffer to be written.
1431e2a5402eSSrinivas Kandagatla  *
1432e2a5402eSSrinivas Kandagatla  * Return: length of bytes written or negative error code on failure.
1433e2a5402eSSrinivas Kandagatla  * */
1434e2a5402eSSrinivas Kandagatla int nvmem_device_write(struct nvmem_device *nvmem,
1435e2a5402eSSrinivas Kandagatla 		       unsigned int offset,
1436e2a5402eSSrinivas Kandagatla 		       size_t bytes, void *buf)
1437e2a5402eSSrinivas Kandagatla {
1438e2a5402eSSrinivas Kandagatla 	int rc;
1439e2a5402eSSrinivas Kandagatla 
1440795ddd18SSrinivas Kandagatla 	if (!nvmem)
1441e2a5402eSSrinivas Kandagatla 		return -EINVAL;
1442e2a5402eSSrinivas Kandagatla 
1443795ddd18SSrinivas Kandagatla 	rc = nvmem_reg_write(nvmem, offset, buf, bytes);
1444e2a5402eSSrinivas Kandagatla 
1445287980e4SArnd Bergmann 	if (rc)
1446e2a5402eSSrinivas Kandagatla 		return rc;
1447e2a5402eSSrinivas Kandagatla 
1448e2a5402eSSrinivas Kandagatla 
1449e2a5402eSSrinivas Kandagatla 	return bytes;
1450e2a5402eSSrinivas Kandagatla }
1451e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_write);
1452e2a5402eSSrinivas Kandagatla 
1453d7b9fd16SBartosz Golaszewski /**
1454b985f4cbSBartosz Golaszewski  * nvmem_add_cell_table() - register a table of cell info entries
1455b985f4cbSBartosz Golaszewski  *
1456b985f4cbSBartosz Golaszewski  * @table: table of cell info entries
1457b985f4cbSBartosz Golaszewski  */
1458b985f4cbSBartosz Golaszewski void nvmem_add_cell_table(struct nvmem_cell_table *table)
1459b985f4cbSBartosz Golaszewski {
1460b985f4cbSBartosz Golaszewski 	mutex_lock(&nvmem_cell_mutex);
1461b985f4cbSBartosz Golaszewski 	list_add_tail(&table->node, &nvmem_cell_tables);
1462b985f4cbSBartosz Golaszewski 	mutex_unlock(&nvmem_cell_mutex);
1463b985f4cbSBartosz Golaszewski }
1464b985f4cbSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_add_cell_table);
1465b985f4cbSBartosz Golaszewski 
1466b985f4cbSBartosz Golaszewski /**
1467b985f4cbSBartosz Golaszewski  * nvmem_del_cell_table() - remove a previously registered cell info table
1468b985f4cbSBartosz Golaszewski  *
1469b985f4cbSBartosz Golaszewski  * @table: table of cell info entries
1470b985f4cbSBartosz Golaszewski  */
1471b985f4cbSBartosz Golaszewski void nvmem_del_cell_table(struct nvmem_cell_table *table)
1472b985f4cbSBartosz Golaszewski {
1473b985f4cbSBartosz Golaszewski 	mutex_lock(&nvmem_cell_mutex);
1474b985f4cbSBartosz Golaszewski 	list_del(&table->node);
1475b985f4cbSBartosz Golaszewski 	mutex_unlock(&nvmem_cell_mutex);
1476b985f4cbSBartosz Golaszewski }
1477b985f4cbSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_del_cell_table);
1478b985f4cbSBartosz Golaszewski 
1479b985f4cbSBartosz Golaszewski /**
1480506157beSBartosz Golaszewski  * nvmem_add_cell_lookups() - register a list of cell lookup entries
1481506157beSBartosz Golaszewski  *
1482506157beSBartosz Golaszewski  * @entries: array of cell lookup entries
1483506157beSBartosz Golaszewski  * @nentries: number of cell lookup entries in the array
1484506157beSBartosz Golaszewski  */
1485506157beSBartosz Golaszewski void nvmem_add_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries)
1486506157beSBartosz Golaszewski {
1487506157beSBartosz Golaszewski 	int i;
1488506157beSBartosz Golaszewski 
1489506157beSBartosz Golaszewski 	mutex_lock(&nvmem_lookup_mutex);
1490506157beSBartosz Golaszewski 	for (i = 0; i < nentries; i++)
1491506157beSBartosz Golaszewski 		list_add_tail(&entries[i].node, &nvmem_lookup_list);
1492506157beSBartosz Golaszewski 	mutex_unlock(&nvmem_lookup_mutex);
1493506157beSBartosz Golaszewski }
1494506157beSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_add_cell_lookups);
1495506157beSBartosz Golaszewski 
1496506157beSBartosz Golaszewski /**
1497506157beSBartosz Golaszewski  * nvmem_del_cell_lookups() - remove a list of previously added cell lookup
1498506157beSBartosz Golaszewski  *                            entries
1499506157beSBartosz Golaszewski  *
1500506157beSBartosz Golaszewski  * @entries: array of cell lookup entries
1501506157beSBartosz Golaszewski  * @nentries: number of cell lookup entries in the array
1502506157beSBartosz Golaszewski  */
1503506157beSBartosz Golaszewski void nvmem_del_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries)
1504506157beSBartosz Golaszewski {
1505506157beSBartosz Golaszewski 	int i;
1506506157beSBartosz Golaszewski 
1507506157beSBartosz Golaszewski 	mutex_lock(&nvmem_lookup_mutex);
1508506157beSBartosz Golaszewski 	for (i = 0; i < nentries; i++)
1509506157beSBartosz Golaszewski 		list_del(&entries[i].node);
1510506157beSBartosz Golaszewski 	mutex_unlock(&nvmem_lookup_mutex);
1511506157beSBartosz Golaszewski }
1512506157beSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_del_cell_lookups);
1513506157beSBartosz Golaszewski 
1514506157beSBartosz Golaszewski /**
1515d7b9fd16SBartosz Golaszewski  * nvmem_dev_name() - Get the name of a given nvmem device.
1516d7b9fd16SBartosz Golaszewski  *
1517d7b9fd16SBartosz Golaszewski  * @nvmem: nvmem device.
1518d7b9fd16SBartosz Golaszewski  *
1519d7b9fd16SBartosz Golaszewski  * Return: name of the nvmem device.
1520d7b9fd16SBartosz Golaszewski  */
1521d7b9fd16SBartosz Golaszewski const char *nvmem_dev_name(struct nvmem_device *nvmem)
1522d7b9fd16SBartosz Golaszewski {
1523d7b9fd16SBartosz Golaszewski 	return dev_name(&nvmem->dev);
1524d7b9fd16SBartosz Golaszewski }
1525d7b9fd16SBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_dev_name);
1526d7b9fd16SBartosz Golaszewski 
1527eace75cfSSrinivas Kandagatla static int __init nvmem_init(void)
1528eace75cfSSrinivas Kandagatla {
1529eace75cfSSrinivas Kandagatla 	return bus_register(&nvmem_bus_type);
1530eace75cfSSrinivas Kandagatla }
1531eace75cfSSrinivas Kandagatla 
1532eace75cfSSrinivas Kandagatla static void __exit nvmem_exit(void)
1533eace75cfSSrinivas Kandagatla {
1534eace75cfSSrinivas Kandagatla 	bus_unregister(&nvmem_bus_type);
1535eace75cfSSrinivas Kandagatla }
1536eace75cfSSrinivas Kandagatla 
1537eace75cfSSrinivas Kandagatla subsys_initcall(nvmem_init);
1538eace75cfSSrinivas Kandagatla module_exit(nvmem_exit);
1539eace75cfSSrinivas Kandagatla 
1540eace75cfSSrinivas Kandagatla MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org");
1541eace75cfSSrinivas Kandagatla MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com");
1542eace75cfSSrinivas Kandagatla MODULE_DESCRIPTION("nvmem Driver Core");
1543eace75cfSSrinivas Kandagatla MODULE_LICENSE("GPL v2");
1544