xref: /linux/drivers/nvmem/core.c (revision badcdff107cbfd7fef5f089260177efc56fe1a9f)
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",
157e7e07f4fSBartosz Golaszewski 		.mode	= 0644,
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",
181e7e07f4fSBartosz Golaszewski 		.mode	= 0444,
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",
204e7e07f4fSBartosz Golaszewski 		.mode	= 0600,
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",
228e7e07f4fSBartosz Golaszewski 		.mode	= 0400,
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);
301*badcdff1SRob Herring 	kfree(cell->name);
302eace75cfSSrinivas Kandagatla 	kfree(cell);
303eace75cfSSrinivas Kandagatla }
304eace75cfSSrinivas Kandagatla 
305eace75cfSSrinivas Kandagatla static void nvmem_device_remove_all_cells(const struct nvmem_device *nvmem)
306eace75cfSSrinivas Kandagatla {
3071852183eSBartosz Golaszewski 	struct nvmem_cell *cell, *p;
308eace75cfSSrinivas Kandagatla 
309c7235ee3SBartosz Golaszewski 	list_for_each_entry_safe(cell, p, &nvmem->cells, node)
310eace75cfSSrinivas Kandagatla 		nvmem_cell_drop(cell);
311eace75cfSSrinivas Kandagatla }
312eace75cfSSrinivas Kandagatla 
313eace75cfSSrinivas Kandagatla static void nvmem_cell_add(struct nvmem_cell *cell)
314eace75cfSSrinivas Kandagatla {
315c7235ee3SBartosz Golaszewski 	mutex_lock(&nvmem_mutex);
316c7235ee3SBartosz Golaszewski 	list_add_tail(&cell->node, &cell->nvmem->cells);
317c7235ee3SBartosz Golaszewski 	mutex_unlock(&nvmem_mutex);
318bee1138bSBartosz Golaszewski 	blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_ADD, cell);
319eace75cfSSrinivas Kandagatla }
320eace75cfSSrinivas Kandagatla 
321eace75cfSSrinivas Kandagatla static int nvmem_cell_info_to_nvmem_cell(struct nvmem_device *nvmem,
322eace75cfSSrinivas Kandagatla 				   const struct nvmem_cell_info *info,
323eace75cfSSrinivas Kandagatla 				   struct nvmem_cell *cell)
324eace75cfSSrinivas Kandagatla {
325eace75cfSSrinivas Kandagatla 	cell->nvmem = nvmem;
326eace75cfSSrinivas Kandagatla 	cell->offset = info->offset;
327eace75cfSSrinivas Kandagatla 	cell->bytes = info->bytes;
328eace75cfSSrinivas Kandagatla 	cell->name = info->name;
329eace75cfSSrinivas Kandagatla 
330eace75cfSSrinivas Kandagatla 	cell->bit_offset = info->bit_offset;
331eace75cfSSrinivas Kandagatla 	cell->nbits = info->nbits;
332eace75cfSSrinivas Kandagatla 
333eace75cfSSrinivas Kandagatla 	if (cell->nbits)
334eace75cfSSrinivas Kandagatla 		cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset,
335eace75cfSSrinivas Kandagatla 					   BITS_PER_BYTE);
336eace75cfSSrinivas Kandagatla 
337eace75cfSSrinivas Kandagatla 	if (!IS_ALIGNED(cell->offset, nvmem->stride)) {
338eace75cfSSrinivas Kandagatla 		dev_err(&nvmem->dev,
339eace75cfSSrinivas Kandagatla 			"cell %s unaligned to nvmem stride %d\n",
340eace75cfSSrinivas Kandagatla 			cell->name, nvmem->stride);
341eace75cfSSrinivas Kandagatla 		return -EINVAL;
342eace75cfSSrinivas Kandagatla 	}
343eace75cfSSrinivas Kandagatla 
344eace75cfSSrinivas Kandagatla 	return 0;
345eace75cfSSrinivas Kandagatla }
346eace75cfSSrinivas Kandagatla 
347b3db17e4SAndrew Lunn /**
348b3db17e4SAndrew Lunn  * nvmem_add_cells() - Add cell information to an nvmem device
349b3db17e4SAndrew Lunn  *
350b3db17e4SAndrew Lunn  * @nvmem: nvmem device to add cells to.
351b3db17e4SAndrew Lunn  * @info: nvmem cell info to add to the device
352b3db17e4SAndrew Lunn  * @ncells: number of cells in info
353b3db17e4SAndrew Lunn  *
354b3db17e4SAndrew Lunn  * Return: 0 or negative error code on failure.
355b3db17e4SAndrew Lunn  */
356ef92ab30SSrinivas Kandagatla static int nvmem_add_cells(struct nvmem_device *nvmem,
357b3db17e4SAndrew Lunn 		    const struct nvmem_cell_info *info,
358b3db17e4SAndrew Lunn 		    int ncells)
359eace75cfSSrinivas Kandagatla {
360eace75cfSSrinivas Kandagatla 	struct nvmem_cell **cells;
361eace75cfSSrinivas Kandagatla 	int i, rval;
362eace75cfSSrinivas Kandagatla 
363b3db17e4SAndrew Lunn 	cells = kcalloc(ncells, sizeof(*cells), GFP_KERNEL);
364eace75cfSSrinivas Kandagatla 	if (!cells)
365eace75cfSSrinivas Kandagatla 		return -ENOMEM;
366eace75cfSSrinivas Kandagatla 
367b3db17e4SAndrew Lunn 	for (i = 0; i < ncells; i++) {
368eace75cfSSrinivas Kandagatla 		cells[i] = kzalloc(sizeof(**cells), GFP_KERNEL);
369eace75cfSSrinivas Kandagatla 		if (!cells[i]) {
370eace75cfSSrinivas Kandagatla 			rval = -ENOMEM;
371eace75cfSSrinivas Kandagatla 			goto err;
372eace75cfSSrinivas Kandagatla 		}
373eace75cfSSrinivas Kandagatla 
374eace75cfSSrinivas Kandagatla 		rval = nvmem_cell_info_to_nvmem_cell(nvmem, &info[i], cells[i]);
375287980e4SArnd Bergmann 		if (rval) {
376eace75cfSSrinivas Kandagatla 			kfree(cells[i]);
377eace75cfSSrinivas Kandagatla 			goto err;
378eace75cfSSrinivas Kandagatla 		}
379eace75cfSSrinivas Kandagatla 
380eace75cfSSrinivas Kandagatla 		nvmem_cell_add(cells[i]);
381eace75cfSSrinivas Kandagatla 	}
382eace75cfSSrinivas Kandagatla 
383eace75cfSSrinivas Kandagatla 	/* remove tmp array */
384eace75cfSSrinivas Kandagatla 	kfree(cells);
385eace75cfSSrinivas Kandagatla 
386eace75cfSSrinivas Kandagatla 	return 0;
387eace75cfSSrinivas Kandagatla err:
388dfdf1414SRasmus Villemoes 	while (i--)
389eace75cfSSrinivas Kandagatla 		nvmem_cell_drop(cells[i]);
390eace75cfSSrinivas Kandagatla 
391dfdf1414SRasmus Villemoes 	kfree(cells);
392dfdf1414SRasmus Villemoes 
393eace75cfSSrinivas Kandagatla 	return rval;
394eace75cfSSrinivas Kandagatla }
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);
551*badcdff1SRob Herring 		cell->name = kasprintf(GFP_KERNEL, "%pOFn", child);
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. */
568*badcdff1SRob Herring 			kfree(cell->name);
569e888d445SBartosz Golaszewski 			kfree(cell);
570e888d445SBartosz Golaszewski 			return -EINVAL;
571e888d445SBartosz Golaszewski 		}
572e888d445SBartosz Golaszewski 
573e888d445SBartosz Golaszewski 		nvmem_cell_add(cell);
574e888d445SBartosz Golaszewski 	}
575e888d445SBartosz Golaszewski 
576e888d445SBartosz Golaszewski 	return 0;
577e888d445SBartosz Golaszewski }
578e888d445SBartosz Golaszewski 
579eace75cfSSrinivas Kandagatla /**
580eace75cfSSrinivas Kandagatla  * nvmem_register() - Register a nvmem device for given nvmem_config.
581eace75cfSSrinivas Kandagatla  * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem
582eace75cfSSrinivas Kandagatla  *
583eace75cfSSrinivas Kandagatla  * @config: nvmem device configuration with which nvmem device is created.
584eace75cfSSrinivas Kandagatla  *
585eace75cfSSrinivas Kandagatla  * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device
586eace75cfSSrinivas Kandagatla  * on success.
587eace75cfSSrinivas Kandagatla  */
588eace75cfSSrinivas Kandagatla 
589eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem_register(const struct nvmem_config *config)
590eace75cfSSrinivas Kandagatla {
591eace75cfSSrinivas Kandagatla 	struct nvmem_device *nvmem;
592eace75cfSSrinivas Kandagatla 	int rval;
593eace75cfSSrinivas Kandagatla 
594eace75cfSSrinivas Kandagatla 	if (!config->dev)
595eace75cfSSrinivas Kandagatla 		return ERR_PTR(-EINVAL);
596eace75cfSSrinivas Kandagatla 
597eace75cfSSrinivas Kandagatla 	nvmem = kzalloc(sizeof(*nvmem), GFP_KERNEL);
598eace75cfSSrinivas Kandagatla 	if (!nvmem)
599eace75cfSSrinivas Kandagatla 		return ERR_PTR(-ENOMEM);
600eace75cfSSrinivas Kandagatla 
601eace75cfSSrinivas Kandagatla 	rval  = ida_simple_get(&nvmem_ida, 0, 0, GFP_KERNEL);
602eace75cfSSrinivas Kandagatla 	if (rval < 0) {
603eace75cfSSrinivas Kandagatla 		kfree(nvmem);
604eace75cfSSrinivas Kandagatla 		return ERR_PTR(rval);
605eace75cfSSrinivas Kandagatla 	}
606eace75cfSSrinivas Kandagatla 
607c1de7f43SBartosz Golaszewski 	kref_init(&nvmem->refcnt);
608c7235ee3SBartosz Golaszewski 	INIT_LIST_HEAD(&nvmem->cells);
609c1de7f43SBartosz Golaszewski 
610eace75cfSSrinivas Kandagatla 	nvmem->id = rval;
611eace75cfSSrinivas Kandagatla 	nvmem->owner = config->owner;
61217eb18d6SMasahiro Yamada 	if (!nvmem->owner && config->dev->driver)
61317eb18d6SMasahiro Yamada 		nvmem->owner = config->dev->driver->owner;
61499897efdSHeiner Kallweit 	nvmem->stride = config->stride ?: 1;
61599897efdSHeiner Kallweit 	nvmem->word_size = config->word_size ?: 1;
616795ddd18SSrinivas Kandagatla 	nvmem->size = config->size;
617eace75cfSSrinivas Kandagatla 	nvmem->dev.type = &nvmem_provider_type;
618eace75cfSSrinivas Kandagatla 	nvmem->dev.bus = &nvmem_bus_type;
619eace75cfSSrinivas Kandagatla 	nvmem->dev.parent = config->dev;
620795ddd18SSrinivas Kandagatla 	nvmem->priv = config->priv;
621795ddd18SSrinivas Kandagatla 	nvmem->reg_read = config->reg_read;
622795ddd18SSrinivas Kandagatla 	nvmem->reg_write = config->reg_write;
623fc2f9970SHeiner Kallweit 	nvmem->dev.of_node = config->dev->of_node;
624fd0f4906SAndrey Smirnov 
625fd0f4906SAndrey Smirnov 	if (config->id == -1 && config->name) {
626fd0f4906SAndrey Smirnov 		dev_set_name(&nvmem->dev, "%s", config->name);
627fd0f4906SAndrey Smirnov 	} else {
628eace75cfSSrinivas Kandagatla 		dev_set_name(&nvmem->dev, "%s%d",
6295253193dSAban Bedel 			     config->name ? : "nvmem",
6305253193dSAban Bedel 			     config->name ? config->id : nvmem->id);
631fd0f4906SAndrey Smirnov 	}
632eace75cfSSrinivas Kandagatla 
633fc2f9970SHeiner Kallweit 	nvmem->read_only = device_property_present(config->dev, "read-only") |
634eace75cfSSrinivas Kandagatla 			   config->read_only;
635eace75cfSSrinivas Kandagatla 
636811b0d65SAndrew Lunn 	if (config->root_only)
637811b0d65SAndrew Lunn 		nvmem->dev.groups = nvmem->read_only ?
638811b0d65SAndrew Lunn 			nvmem_ro_root_dev_groups :
639811b0d65SAndrew Lunn 			nvmem_rw_root_dev_groups;
640811b0d65SAndrew Lunn 	else
641811b0d65SAndrew Lunn 		nvmem->dev.groups = nvmem->read_only ?
642811b0d65SAndrew Lunn 			nvmem_ro_dev_groups :
643eace75cfSSrinivas Kandagatla 			nvmem_rw_dev_groups;
644eace75cfSSrinivas Kandagatla 
645eace75cfSSrinivas Kandagatla 	device_initialize(&nvmem->dev);
646eace75cfSSrinivas Kandagatla 
647eace75cfSSrinivas Kandagatla 	dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name);
648eace75cfSSrinivas Kandagatla 
649eace75cfSSrinivas Kandagatla 	rval = device_add(&nvmem->dev);
650b6c217abSAndrew Lunn 	if (rval)
6513360acdfSJohan Hovold 		goto err_put_device;
652b6c217abSAndrew Lunn 
653b6c217abSAndrew Lunn 	if (config->compat) {
654b6c217abSAndrew Lunn 		rval = nvmem_setup_compat(nvmem, config);
655b6c217abSAndrew Lunn 		if (rval)
6563360acdfSJohan Hovold 			goto err_device_del;
657eace75cfSSrinivas Kandagatla 	}
658eace75cfSSrinivas Kandagatla 
659fa72d847SBartosz Golaszewski 	if (config->cells) {
660fa72d847SBartosz Golaszewski 		rval = nvmem_add_cells(nvmem, config->cells, config->ncells);
661fa72d847SBartosz Golaszewski 		if (rval)
662fa72d847SBartosz Golaszewski 			goto err_teardown_compat;
663fa72d847SBartosz Golaszewski 	}
664eace75cfSSrinivas Kandagatla 
665b985f4cbSBartosz Golaszewski 	rval = nvmem_add_cells_from_table(nvmem);
666b985f4cbSBartosz Golaszewski 	if (rval)
667b985f4cbSBartosz Golaszewski 		goto err_remove_cells;
668b985f4cbSBartosz Golaszewski 
669e888d445SBartosz Golaszewski 	rval = nvmem_add_cells_from_of(nvmem);
670e888d445SBartosz Golaszewski 	if (rval)
671e888d445SBartosz Golaszewski 		goto err_remove_cells;
672e888d445SBartosz Golaszewski 
673bee1138bSBartosz Golaszewski 	rval = blocking_notifier_call_chain(&nvmem_notifier, NVMEM_ADD, nvmem);
674bee1138bSBartosz Golaszewski 	if (rval)
675bee1138bSBartosz Golaszewski 		goto err_remove_cells;
676bee1138bSBartosz Golaszewski 
677eace75cfSSrinivas Kandagatla 	return nvmem;
6783360acdfSJohan Hovold 
679b985f4cbSBartosz Golaszewski err_remove_cells:
680b985f4cbSBartosz Golaszewski 	nvmem_device_remove_all_cells(nvmem);
681fa72d847SBartosz Golaszewski err_teardown_compat:
682fa72d847SBartosz Golaszewski 	if (config->compat)
683fa72d847SBartosz Golaszewski 		device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom);
6843360acdfSJohan Hovold err_device_del:
6853360acdfSJohan Hovold 	device_del(&nvmem->dev);
6863360acdfSJohan Hovold err_put_device:
6873360acdfSJohan Hovold 	put_device(&nvmem->dev);
6883360acdfSJohan Hovold 
689b6c217abSAndrew Lunn 	return ERR_PTR(rval);
690eace75cfSSrinivas Kandagatla }
691eace75cfSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_register);
692eace75cfSSrinivas Kandagatla 
693c1de7f43SBartosz Golaszewski static void nvmem_device_release(struct kref *kref)
694c1de7f43SBartosz Golaszewski {
695c1de7f43SBartosz Golaszewski 	struct nvmem_device *nvmem;
696c1de7f43SBartosz Golaszewski 
697c1de7f43SBartosz Golaszewski 	nvmem = container_of(kref, struct nvmem_device, refcnt);
698c1de7f43SBartosz Golaszewski 
699bee1138bSBartosz Golaszewski 	blocking_notifier_call_chain(&nvmem_notifier, NVMEM_REMOVE, nvmem);
700bee1138bSBartosz Golaszewski 
701c1de7f43SBartosz Golaszewski 	if (nvmem->flags & FLAG_COMPAT)
702c1de7f43SBartosz Golaszewski 		device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom);
703c1de7f43SBartosz Golaszewski 
704c1de7f43SBartosz Golaszewski 	nvmem_device_remove_all_cells(nvmem);
705c1de7f43SBartosz Golaszewski 	device_del(&nvmem->dev);
706c1de7f43SBartosz Golaszewski 	put_device(&nvmem->dev);
707c1de7f43SBartosz Golaszewski }
708c1de7f43SBartosz Golaszewski 
709eace75cfSSrinivas Kandagatla /**
710eace75cfSSrinivas Kandagatla  * nvmem_unregister() - Unregister previously registered nvmem device
711eace75cfSSrinivas Kandagatla  *
712eace75cfSSrinivas Kandagatla  * @nvmem: Pointer to previously registered nvmem device.
713eace75cfSSrinivas Kandagatla  */
714bf58e882SBartosz Golaszewski void nvmem_unregister(struct nvmem_device *nvmem)
715eace75cfSSrinivas Kandagatla {
716c1de7f43SBartosz Golaszewski 	kref_put(&nvmem->refcnt, nvmem_device_release);
717eace75cfSSrinivas Kandagatla }
718eace75cfSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_unregister);
719eace75cfSSrinivas Kandagatla 
720f1f50ecaSAndrey Smirnov static void devm_nvmem_release(struct device *dev, void *res)
721f1f50ecaSAndrey Smirnov {
722bf58e882SBartosz Golaszewski 	nvmem_unregister(*(struct nvmem_device **)res);
723f1f50ecaSAndrey Smirnov }
724f1f50ecaSAndrey Smirnov 
725f1f50ecaSAndrey Smirnov /**
726f1f50ecaSAndrey Smirnov  * devm_nvmem_register() - Register a managed nvmem device for given
727f1f50ecaSAndrey Smirnov  * nvmem_config.
728f1f50ecaSAndrey Smirnov  * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem
729f1f50ecaSAndrey Smirnov  *
730b378c779SSrinivas Kandagatla  * @dev: Device that uses the nvmem device.
731f1f50ecaSAndrey Smirnov  * @config: nvmem device configuration with which nvmem device is created.
732f1f50ecaSAndrey Smirnov  *
733f1f50ecaSAndrey Smirnov  * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device
734f1f50ecaSAndrey Smirnov  * on success.
735f1f50ecaSAndrey Smirnov  */
736f1f50ecaSAndrey Smirnov struct nvmem_device *devm_nvmem_register(struct device *dev,
737f1f50ecaSAndrey Smirnov 					 const struct nvmem_config *config)
738f1f50ecaSAndrey Smirnov {
739f1f50ecaSAndrey Smirnov 	struct nvmem_device **ptr, *nvmem;
740f1f50ecaSAndrey Smirnov 
741f1f50ecaSAndrey Smirnov 	ptr = devres_alloc(devm_nvmem_release, sizeof(*ptr), GFP_KERNEL);
742f1f50ecaSAndrey Smirnov 	if (!ptr)
743f1f50ecaSAndrey Smirnov 		return ERR_PTR(-ENOMEM);
744f1f50ecaSAndrey Smirnov 
745f1f50ecaSAndrey Smirnov 	nvmem = nvmem_register(config);
746f1f50ecaSAndrey Smirnov 
747f1f50ecaSAndrey Smirnov 	if (!IS_ERR(nvmem)) {
748f1f50ecaSAndrey Smirnov 		*ptr = nvmem;
749f1f50ecaSAndrey Smirnov 		devres_add(dev, ptr);
750f1f50ecaSAndrey Smirnov 	} else {
751f1f50ecaSAndrey Smirnov 		devres_free(ptr);
752f1f50ecaSAndrey Smirnov 	}
753f1f50ecaSAndrey Smirnov 
754f1f50ecaSAndrey Smirnov 	return nvmem;
755f1f50ecaSAndrey Smirnov }
756f1f50ecaSAndrey Smirnov EXPORT_SYMBOL_GPL(devm_nvmem_register);
757f1f50ecaSAndrey Smirnov 
758f1f50ecaSAndrey Smirnov static int devm_nvmem_match(struct device *dev, void *res, void *data)
759f1f50ecaSAndrey Smirnov {
760f1f50ecaSAndrey Smirnov 	struct nvmem_device **r = res;
761f1f50ecaSAndrey Smirnov 
762f1f50ecaSAndrey Smirnov 	return *r == data;
763f1f50ecaSAndrey Smirnov }
764f1f50ecaSAndrey Smirnov 
765f1f50ecaSAndrey Smirnov /**
766f1f50ecaSAndrey Smirnov  * devm_nvmem_unregister() - Unregister previously registered managed nvmem
767f1f50ecaSAndrey Smirnov  * device.
768f1f50ecaSAndrey Smirnov  *
769b378c779SSrinivas Kandagatla  * @dev: Device that uses the nvmem device.
770f1f50ecaSAndrey Smirnov  * @nvmem: Pointer to previously registered nvmem device.
771f1f50ecaSAndrey Smirnov  *
772f1f50ecaSAndrey Smirnov  * Return: Will be an negative on error or a zero on success.
773f1f50ecaSAndrey Smirnov  */
774f1f50ecaSAndrey Smirnov int devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem)
775f1f50ecaSAndrey Smirnov {
776f1f50ecaSAndrey Smirnov 	return devres_release(dev, devm_nvmem_release, devm_nvmem_match, nvmem);
777f1f50ecaSAndrey Smirnov }
778f1f50ecaSAndrey Smirnov EXPORT_SYMBOL(devm_nvmem_unregister);
779f1f50ecaSAndrey Smirnov 
78069aba794SSrinivas Kandagatla static struct nvmem_device *__nvmem_device_get(struct device_node *np,
781506157beSBartosz Golaszewski 					       const char *nvmem_name)
78269aba794SSrinivas Kandagatla {
78369aba794SSrinivas Kandagatla 	struct nvmem_device *nvmem = NULL;
78469aba794SSrinivas Kandagatla 
785c7235ee3SBartosz Golaszewski 	mutex_lock(&nvmem_mutex);
786506157beSBartosz Golaszewski 	nvmem = np ? of_nvmem_find(np) : nvmem_find(nvmem_name);
78769aba794SSrinivas Kandagatla 	mutex_unlock(&nvmem_mutex);
788c7235ee3SBartosz Golaszewski 	if (!nvmem)
789c7235ee3SBartosz Golaszewski 		return ERR_PTR(-EPROBE_DEFER);
79069aba794SSrinivas Kandagatla 
79169aba794SSrinivas Kandagatla 	if (!try_module_get(nvmem->owner)) {
79269aba794SSrinivas Kandagatla 		dev_err(&nvmem->dev,
79369aba794SSrinivas Kandagatla 			"could not increase module refcount for cell %s\n",
7945db652c9SBartosz Golaszewski 			nvmem_dev_name(nvmem));
79569aba794SSrinivas Kandagatla 
79669aba794SSrinivas Kandagatla 		return ERR_PTR(-EINVAL);
79769aba794SSrinivas Kandagatla 	}
79869aba794SSrinivas Kandagatla 
799c1de7f43SBartosz Golaszewski 	kref_get(&nvmem->refcnt);
800c1de7f43SBartosz Golaszewski 
80169aba794SSrinivas Kandagatla 	return nvmem;
80269aba794SSrinivas Kandagatla }
80369aba794SSrinivas Kandagatla 
80469aba794SSrinivas Kandagatla static void __nvmem_device_put(struct nvmem_device *nvmem)
80569aba794SSrinivas Kandagatla {
80669aba794SSrinivas Kandagatla 	module_put(nvmem->owner);
807c1de7f43SBartosz Golaszewski 	kref_put(&nvmem->refcnt, nvmem_device_release);
80869aba794SSrinivas Kandagatla }
80969aba794SSrinivas Kandagatla 
810e701c67cSMasahiro Yamada #if IS_ENABLED(CONFIG_OF)
811e2a5402eSSrinivas Kandagatla /**
812e2a5402eSSrinivas Kandagatla  * of_nvmem_device_get() - Get nvmem device from a given id
813e2a5402eSSrinivas Kandagatla  *
81429143268SVivek Gautam  * @np: Device tree node that uses the nvmem device.
815e2a5402eSSrinivas Kandagatla  * @id: nvmem name from nvmem-names property.
816e2a5402eSSrinivas Kandagatla  *
817e2a5402eSSrinivas Kandagatla  * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device
818e2a5402eSSrinivas Kandagatla  * on success.
819e2a5402eSSrinivas Kandagatla  */
820e2a5402eSSrinivas Kandagatla struct nvmem_device *of_nvmem_device_get(struct device_node *np, const char *id)
821e2a5402eSSrinivas Kandagatla {
822e2a5402eSSrinivas Kandagatla 
823e2a5402eSSrinivas Kandagatla 	struct device_node *nvmem_np;
824e2a5402eSSrinivas Kandagatla 	int index;
825e2a5402eSSrinivas Kandagatla 
826e2a5402eSSrinivas Kandagatla 	index = of_property_match_string(np, "nvmem-names", id);
827e2a5402eSSrinivas Kandagatla 
828e2a5402eSSrinivas Kandagatla 	nvmem_np = of_parse_phandle(np, "nvmem", index);
829e2a5402eSSrinivas Kandagatla 	if (!nvmem_np)
830e2a5402eSSrinivas Kandagatla 		return ERR_PTR(-EINVAL);
831e2a5402eSSrinivas Kandagatla 
832506157beSBartosz Golaszewski 	return __nvmem_device_get(nvmem_np, NULL);
833e2a5402eSSrinivas Kandagatla }
834e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_nvmem_device_get);
835e2a5402eSSrinivas Kandagatla #endif
836e2a5402eSSrinivas Kandagatla 
837e2a5402eSSrinivas Kandagatla /**
838e2a5402eSSrinivas Kandagatla  * nvmem_device_get() - Get nvmem device from a given id
839e2a5402eSSrinivas Kandagatla  *
84029143268SVivek Gautam  * @dev: Device that uses the nvmem device.
84129143268SVivek Gautam  * @dev_name: name of the requested nvmem device.
842e2a5402eSSrinivas Kandagatla  *
843e2a5402eSSrinivas Kandagatla  * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device
844e2a5402eSSrinivas Kandagatla  * on success.
845e2a5402eSSrinivas Kandagatla  */
846e2a5402eSSrinivas Kandagatla struct nvmem_device *nvmem_device_get(struct device *dev, const char *dev_name)
847e2a5402eSSrinivas Kandagatla {
848e2a5402eSSrinivas Kandagatla 	if (dev->of_node) { /* try dt first */
849e2a5402eSSrinivas Kandagatla 		struct nvmem_device *nvmem;
850e2a5402eSSrinivas Kandagatla 
851e2a5402eSSrinivas Kandagatla 		nvmem = of_nvmem_device_get(dev->of_node, dev_name);
852e2a5402eSSrinivas Kandagatla 
853e2a5402eSSrinivas Kandagatla 		if (!IS_ERR(nvmem) || PTR_ERR(nvmem) == -EPROBE_DEFER)
854e2a5402eSSrinivas Kandagatla 			return nvmem;
855e2a5402eSSrinivas Kandagatla 
856e2a5402eSSrinivas Kandagatla 	}
857e2a5402eSSrinivas Kandagatla 
858e2a5402eSSrinivas Kandagatla 	return nvmem_find(dev_name);
859e2a5402eSSrinivas Kandagatla }
860e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_get);
861e2a5402eSSrinivas Kandagatla 
862e2a5402eSSrinivas Kandagatla static int devm_nvmem_device_match(struct device *dev, void *res, void *data)
863e2a5402eSSrinivas Kandagatla {
864e2a5402eSSrinivas Kandagatla 	struct nvmem_device **nvmem = res;
865e2a5402eSSrinivas Kandagatla 
866e2a5402eSSrinivas Kandagatla 	if (WARN_ON(!nvmem || !*nvmem))
867e2a5402eSSrinivas Kandagatla 		return 0;
868e2a5402eSSrinivas Kandagatla 
869e2a5402eSSrinivas Kandagatla 	return *nvmem == data;
870e2a5402eSSrinivas Kandagatla }
871e2a5402eSSrinivas Kandagatla 
872e2a5402eSSrinivas Kandagatla static void devm_nvmem_device_release(struct device *dev, void *res)
873e2a5402eSSrinivas Kandagatla {
874e2a5402eSSrinivas Kandagatla 	nvmem_device_put(*(struct nvmem_device **)res);
875e2a5402eSSrinivas Kandagatla }
876e2a5402eSSrinivas Kandagatla 
877e2a5402eSSrinivas Kandagatla /**
878e2a5402eSSrinivas Kandagatla  * devm_nvmem_device_put() - put alredy got nvmem device
879e2a5402eSSrinivas Kandagatla  *
88029143268SVivek Gautam  * @dev: Device that uses the nvmem device.
881e2a5402eSSrinivas Kandagatla  * @nvmem: pointer to nvmem device allocated by devm_nvmem_cell_get(),
882e2a5402eSSrinivas Kandagatla  * that needs to be released.
883e2a5402eSSrinivas Kandagatla  */
884e2a5402eSSrinivas Kandagatla void devm_nvmem_device_put(struct device *dev, struct nvmem_device *nvmem)
885e2a5402eSSrinivas Kandagatla {
886e2a5402eSSrinivas Kandagatla 	int ret;
887e2a5402eSSrinivas Kandagatla 
888e2a5402eSSrinivas Kandagatla 	ret = devres_release(dev, devm_nvmem_device_release,
889e2a5402eSSrinivas Kandagatla 			     devm_nvmem_device_match, nvmem);
890e2a5402eSSrinivas Kandagatla 
891e2a5402eSSrinivas Kandagatla 	WARN_ON(ret);
892e2a5402eSSrinivas Kandagatla }
893e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_device_put);
894e2a5402eSSrinivas Kandagatla 
895e2a5402eSSrinivas Kandagatla /**
896e2a5402eSSrinivas Kandagatla  * nvmem_device_put() - put alredy got nvmem device
897e2a5402eSSrinivas Kandagatla  *
898e2a5402eSSrinivas Kandagatla  * @nvmem: pointer to nvmem device that needs to be released.
899e2a5402eSSrinivas Kandagatla  */
900e2a5402eSSrinivas Kandagatla void nvmem_device_put(struct nvmem_device *nvmem)
901e2a5402eSSrinivas Kandagatla {
902e2a5402eSSrinivas Kandagatla 	__nvmem_device_put(nvmem);
903e2a5402eSSrinivas Kandagatla }
904e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_put);
905e2a5402eSSrinivas Kandagatla 
906e2a5402eSSrinivas Kandagatla /**
907e2a5402eSSrinivas Kandagatla  * devm_nvmem_device_get() - Get nvmem cell of device form a given id
908e2a5402eSSrinivas Kandagatla  *
90929143268SVivek Gautam  * @dev: Device that requests the nvmem device.
91029143268SVivek Gautam  * @id: name id for the requested nvmem device.
911e2a5402eSSrinivas Kandagatla  *
912e2a5402eSSrinivas Kandagatla  * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_cell
913e2a5402eSSrinivas Kandagatla  * on success.  The nvmem_cell will be freed by the automatically once the
914e2a5402eSSrinivas Kandagatla  * device is freed.
915e2a5402eSSrinivas Kandagatla  */
916e2a5402eSSrinivas Kandagatla struct nvmem_device *devm_nvmem_device_get(struct device *dev, const char *id)
917e2a5402eSSrinivas Kandagatla {
918e2a5402eSSrinivas Kandagatla 	struct nvmem_device **ptr, *nvmem;
919e2a5402eSSrinivas Kandagatla 
920e2a5402eSSrinivas Kandagatla 	ptr = devres_alloc(devm_nvmem_device_release, sizeof(*ptr), GFP_KERNEL);
921e2a5402eSSrinivas Kandagatla 	if (!ptr)
922e2a5402eSSrinivas Kandagatla 		return ERR_PTR(-ENOMEM);
923e2a5402eSSrinivas Kandagatla 
924e2a5402eSSrinivas Kandagatla 	nvmem = nvmem_device_get(dev, id);
925e2a5402eSSrinivas Kandagatla 	if (!IS_ERR(nvmem)) {
926e2a5402eSSrinivas Kandagatla 		*ptr = nvmem;
927e2a5402eSSrinivas Kandagatla 		devres_add(dev, ptr);
928e2a5402eSSrinivas Kandagatla 	} else {
929e2a5402eSSrinivas Kandagatla 		devres_free(ptr);
930e2a5402eSSrinivas Kandagatla 	}
931e2a5402eSSrinivas Kandagatla 
932e2a5402eSSrinivas Kandagatla 	return nvmem;
933e2a5402eSSrinivas Kandagatla }
934e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_device_get);
935e2a5402eSSrinivas Kandagatla 
936506157beSBartosz Golaszewski static struct nvmem_cell *
937506157beSBartosz Golaszewski nvmem_cell_get_from_lookup(struct device *dev, const char *con_id)
93869aba794SSrinivas Kandagatla {
939506157beSBartosz Golaszewski 	struct nvmem_cell *cell = ERR_PTR(-ENOENT);
940506157beSBartosz Golaszewski 	struct nvmem_cell_lookup *lookup;
94169aba794SSrinivas Kandagatla 	struct nvmem_device *nvmem;
942506157beSBartosz Golaszewski 	const char *dev_id;
94369aba794SSrinivas Kandagatla 
944506157beSBartosz Golaszewski 	if (!dev)
945506157beSBartosz Golaszewski 		return ERR_PTR(-EINVAL);
94669aba794SSrinivas Kandagatla 
947506157beSBartosz Golaszewski 	dev_id = dev_name(dev);
948506157beSBartosz Golaszewski 
949506157beSBartosz Golaszewski 	mutex_lock(&nvmem_lookup_mutex);
950506157beSBartosz Golaszewski 
951506157beSBartosz Golaszewski 	list_for_each_entry(lookup, &nvmem_lookup_list, node) {
952506157beSBartosz Golaszewski 		if ((strcmp(lookup->dev_id, dev_id) == 0) &&
953506157beSBartosz Golaszewski 		    (strcmp(lookup->con_id, con_id) == 0)) {
954506157beSBartosz Golaszewski 			/* This is the right entry. */
955506157beSBartosz Golaszewski 			nvmem = __nvmem_device_get(NULL, lookup->nvmem_name);
956506157beSBartosz Golaszewski 			if (!nvmem) {
957506157beSBartosz Golaszewski 				/* Provider may not be registered yet. */
958506157beSBartosz Golaszewski 				cell = ERR_PTR(-EPROBE_DEFER);
959506157beSBartosz Golaszewski 				goto out;
960506157beSBartosz Golaszewski 			}
961506157beSBartosz Golaszewski 
962506157beSBartosz Golaszewski 			cell = nvmem_find_cell_by_name(nvmem,
963506157beSBartosz Golaszewski 						       lookup->cell_name);
964506157beSBartosz Golaszewski 			if (!cell) {
965506157beSBartosz Golaszewski 				__nvmem_device_put(nvmem);
966506157beSBartosz Golaszewski 				goto out;
967506157beSBartosz Golaszewski 			}
968506157beSBartosz Golaszewski 		}
969506157beSBartosz Golaszewski 	}
970506157beSBartosz Golaszewski 
971506157beSBartosz Golaszewski out:
972506157beSBartosz Golaszewski 	mutex_unlock(&nvmem_lookup_mutex);
97369aba794SSrinivas Kandagatla 	return cell;
97469aba794SSrinivas Kandagatla }
97569aba794SSrinivas Kandagatla 
976e701c67cSMasahiro Yamada #if IS_ENABLED(CONFIG_OF)
97769aba794SSrinivas Kandagatla /**
97869aba794SSrinivas Kandagatla  * of_nvmem_cell_get() - Get a nvmem cell from given device node and cell id
97969aba794SSrinivas Kandagatla  *
98029143268SVivek Gautam  * @np: Device tree node that uses the nvmem cell.
981165589f0SBartosz Golaszewski  * @id: nvmem cell name from nvmem-cell-names property, or NULL
982fd0c478cSVivek Gautam  *      for the cell at index 0 (the lone cell with no accompanying
983fd0c478cSVivek Gautam  *      nvmem-cell-names property).
98469aba794SSrinivas Kandagatla  *
98569aba794SSrinivas Kandagatla  * Return: Will be an ERR_PTR() on error or a valid pointer
98669aba794SSrinivas Kandagatla  * to a struct nvmem_cell.  The nvmem_cell will be freed by the
98769aba794SSrinivas Kandagatla  * nvmem_cell_put().
98869aba794SSrinivas Kandagatla  */
989165589f0SBartosz Golaszewski struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *id)
99069aba794SSrinivas Kandagatla {
99169aba794SSrinivas Kandagatla 	struct device_node *cell_np, *nvmem_np;
99269aba794SSrinivas Kandagatla 	struct nvmem_device *nvmem;
993e888d445SBartosz Golaszewski 	struct nvmem_cell *cell;
994fd0c478cSVivek Gautam 	int index = 0;
99569aba794SSrinivas Kandagatla 
996fd0c478cSVivek Gautam 	/* if cell name exists, find index to the name */
997165589f0SBartosz Golaszewski 	if (id)
998165589f0SBartosz Golaszewski 		index = of_property_match_string(np, "nvmem-cell-names", id);
99969aba794SSrinivas Kandagatla 
100069aba794SSrinivas Kandagatla 	cell_np = of_parse_phandle(np, "nvmem-cells", index);
100169aba794SSrinivas Kandagatla 	if (!cell_np)
100269aba794SSrinivas Kandagatla 		return ERR_PTR(-EINVAL);
100369aba794SSrinivas Kandagatla 
100469aba794SSrinivas Kandagatla 	nvmem_np = of_get_next_parent(cell_np);
100569aba794SSrinivas Kandagatla 	if (!nvmem_np)
100669aba794SSrinivas Kandagatla 		return ERR_PTR(-EINVAL);
100769aba794SSrinivas Kandagatla 
1008506157beSBartosz Golaszewski 	nvmem = __nvmem_device_get(nvmem_np, NULL);
1009aad8d097SMasahiro Yamada 	of_node_put(nvmem_np);
101069aba794SSrinivas Kandagatla 	if (IS_ERR(nvmem))
101169aba794SSrinivas Kandagatla 		return ERR_CAST(nvmem);
101269aba794SSrinivas Kandagatla 
1013e888d445SBartosz Golaszewski 	cell = nvmem_find_cell_by_index(nvmem, index);
101469aba794SSrinivas Kandagatla 	if (!cell) {
1015e888d445SBartosz Golaszewski 		__nvmem_device_put(nvmem);
1016e888d445SBartosz Golaszewski 		return ERR_PTR(-ENOENT);
101769aba794SSrinivas Kandagatla 	}
101869aba794SSrinivas Kandagatla 
101969aba794SSrinivas Kandagatla 	return cell;
102069aba794SSrinivas Kandagatla }
102169aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_nvmem_cell_get);
102269aba794SSrinivas Kandagatla #endif
102369aba794SSrinivas Kandagatla 
102469aba794SSrinivas Kandagatla /**
102569aba794SSrinivas Kandagatla  * nvmem_cell_get() - Get nvmem cell of device form a given cell name
102669aba794SSrinivas Kandagatla  *
102729143268SVivek Gautam  * @dev: Device that requests the nvmem cell.
1028165589f0SBartosz Golaszewski  * @id: nvmem cell name to get (this corresponds with the name from the
1029165589f0SBartosz Golaszewski  *      nvmem-cell-names property for DT systems and with the con_id from
1030165589f0SBartosz Golaszewski  *      the lookup entry for non-DT systems).
103169aba794SSrinivas Kandagatla  *
103269aba794SSrinivas Kandagatla  * Return: Will be an ERR_PTR() on error or a valid pointer
103369aba794SSrinivas Kandagatla  * to a struct nvmem_cell.  The nvmem_cell will be freed by the
103469aba794SSrinivas Kandagatla  * nvmem_cell_put().
103569aba794SSrinivas Kandagatla  */
1036165589f0SBartosz Golaszewski struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *id)
103769aba794SSrinivas Kandagatla {
103869aba794SSrinivas Kandagatla 	struct nvmem_cell *cell;
103969aba794SSrinivas Kandagatla 
104069aba794SSrinivas Kandagatla 	if (dev->of_node) { /* try dt first */
1041165589f0SBartosz Golaszewski 		cell = of_nvmem_cell_get(dev->of_node, id);
104269aba794SSrinivas Kandagatla 		if (!IS_ERR(cell) || PTR_ERR(cell) == -EPROBE_DEFER)
104369aba794SSrinivas Kandagatla 			return cell;
104469aba794SSrinivas Kandagatla 	}
104569aba794SSrinivas Kandagatla 
1046165589f0SBartosz Golaszewski 	/* NULL cell id only allowed for device tree; invalid otherwise */
1047165589f0SBartosz Golaszewski 	if (!id)
104887ed1405SDouglas Anderson 		return ERR_PTR(-EINVAL);
104987ed1405SDouglas Anderson 
1050165589f0SBartosz Golaszewski 	return nvmem_cell_get_from_lookup(dev, id);
105169aba794SSrinivas Kandagatla }
105269aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_get);
105369aba794SSrinivas Kandagatla 
105469aba794SSrinivas Kandagatla static void devm_nvmem_cell_release(struct device *dev, void *res)
105569aba794SSrinivas Kandagatla {
105669aba794SSrinivas Kandagatla 	nvmem_cell_put(*(struct nvmem_cell **)res);
105769aba794SSrinivas Kandagatla }
105869aba794SSrinivas Kandagatla 
105969aba794SSrinivas Kandagatla /**
106069aba794SSrinivas Kandagatla  * devm_nvmem_cell_get() - Get nvmem cell of device form a given id
106169aba794SSrinivas Kandagatla  *
106229143268SVivek Gautam  * @dev: Device that requests the nvmem cell.
106329143268SVivek Gautam  * @id: nvmem cell name id to get.
106469aba794SSrinivas Kandagatla  *
106569aba794SSrinivas Kandagatla  * Return: Will be an ERR_PTR() on error or a valid pointer
106669aba794SSrinivas Kandagatla  * to a struct nvmem_cell.  The nvmem_cell will be freed by the
106769aba794SSrinivas Kandagatla  * automatically once the device is freed.
106869aba794SSrinivas Kandagatla  */
106969aba794SSrinivas Kandagatla struct nvmem_cell *devm_nvmem_cell_get(struct device *dev, const char *id)
107069aba794SSrinivas Kandagatla {
107169aba794SSrinivas Kandagatla 	struct nvmem_cell **ptr, *cell;
107269aba794SSrinivas Kandagatla 
107369aba794SSrinivas Kandagatla 	ptr = devres_alloc(devm_nvmem_cell_release, sizeof(*ptr), GFP_KERNEL);
107469aba794SSrinivas Kandagatla 	if (!ptr)
107569aba794SSrinivas Kandagatla 		return ERR_PTR(-ENOMEM);
107669aba794SSrinivas Kandagatla 
107769aba794SSrinivas Kandagatla 	cell = nvmem_cell_get(dev, id);
107869aba794SSrinivas Kandagatla 	if (!IS_ERR(cell)) {
107969aba794SSrinivas Kandagatla 		*ptr = cell;
108069aba794SSrinivas Kandagatla 		devres_add(dev, ptr);
108169aba794SSrinivas Kandagatla 	} else {
108269aba794SSrinivas Kandagatla 		devres_free(ptr);
108369aba794SSrinivas Kandagatla 	}
108469aba794SSrinivas Kandagatla 
108569aba794SSrinivas Kandagatla 	return cell;
108669aba794SSrinivas Kandagatla }
108769aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_cell_get);
108869aba794SSrinivas Kandagatla 
108969aba794SSrinivas Kandagatla static int devm_nvmem_cell_match(struct device *dev, void *res, void *data)
109069aba794SSrinivas Kandagatla {
109169aba794SSrinivas Kandagatla 	struct nvmem_cell **c = res;
109269aba794SSrinivas Kandagatla 
109369aba794SSrinivas Kandagatla 	if (WARN_ON(!c || !*c))
109469aba794SSrinivas Kandagatla 		return 0;
109569aba794SSrinivas Kandagatla 
109669aba794SSrinivas Kandagatla 	return *c == data;
109769aba794SSrinivas Kandagatla }
109869aba794SSrinivas Kandagatla 
109969aba794SSrinivas Kandagatla /**
110069aba794SSrinivas Kandagatla  * devm_nvmem_cell_put() - Release previously allocated nvmem cell
110169aba794SSrinivas Kandagatla  * from devm_nvmem_cell_get.
110269aba794SSrinivas Kandagatla  *
110329143268SVivek Gautam  * @dev: Device that requests the nvmem cell.
110429143268SVivek Gautam  * @cell: Previously allocated nvmem cell by devm_nvmem_cell_get().
110569aba794SSrinivas Kandagatla  */
110669aba794SSrinivas Kandagatla void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell)
110769aba794SSrinivas Kandagatla {
110869aba794SSrinivas Kandagatla 	int ret;
110969aba794SSrinivas Kandagatla 
111069aba794SSrinivas Kandagatla 	ret = devres_release(dev, devm_nvmem_cell_release,
111169aba794SSrinivas Kandagatla 				devm_nvmem_cell_match, cell);
111269aba794SSrinivas Kandagatla 
111369aba794SSrinivas Kandagatla 	WARN_ON(ret);
111469aba794SSrinivas Kandagatla }
111569aba794SSrinivas Kandagatla EXPORT_SYMBOL(devm_nvmem_cell_put);
111669aba794SSrinivas Kandagatla 
111769aba794SSrinivas Kandagatla /**
111869aba794SSrinivas Kandagatla  * nvmem_cell_put() - Release previously allocated nvmem cell.
111969aba794SSrinivas Kandagatla  *
112029143268SVivek Gautam  * @cell: Previously allocated nvmem cell by nvmem_cell_get().
112169aba794SSrinivas Kandagatla  */
112269aba794SSrinivas Kandagatla void nvmem_cell_put(struct nvmem_cell *cell)
112369aba794SSrinivas Kandagatla {
112469aba794SSrinivas Kandagatla 	struct nvmem_device *nvmem = cell->nvmem;
112569aba794SSrinivas Kandagatla 
112669aba794SSrinivas Kandagatla 	__nvmem_device_put(nvmem);
112769aba794SSrinivas Kandagatla }
112869aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_put);
112969aba794SSrinivas Kandagatla 
1130f7c04f16SMasahiro Yamada static void nvmem_shift_read_buffer_in_place(struct nvmem_cell *cell, void *buf)
113169aba794SSrinivas Kandagatla {
113269aba794SSrinivas Kandagatla 	u8 *p, *b;
113369aba794SSrinivas Kandagatla 	int i, bit_offset = cell->bit_offset;
113469aba794SSrinivas Kandagatla 
113569aba794SSrinivas Kandagatla 	p = b = buf;
113669aba794SSrinivas Kandagatla 	if (bit_offset) {
113769aba794SSrinivas Kandagatla 		/* First shift */
113869aba794SSrinivas Kandagatla 		*b++ >>= bit_offset;
113969aba794SSrinivas Kandagatla 
114069aba794SSrinivas Kandagatla 		/* setup rest of the bytes if any */
114169aba794SSrinivas Kandagatla 		for (i = 1; i < cell->bytes; i++) {
114269aba794SSrinivas Kandagatla 			/* Get bits from next byte and shift them towards msb */
114369aba794SSrinivas Kandagatla 			*p |= *b << (BITS_PER_BYTE - bit_offset);
114469aba794SSrinivas Kandagatla 
114569aba794SSrinivas Kandagatla 			p = b;
114669aba794SSrinivas Kandagatla 			*b++ >>= bit_offset;
114769aba794SSrinivas Kandagatla 		}
114869aba794SSrinivas Kandagatla 
114969aba794SSrinivas Kandagatla 		/* result fits in less bytes */
115069aba794SSrinivas Kandagatla 		if (cell->bytes != DIV_ROUND_UP(cell->nbits, BITS_PER_BYTE))
115169aba794SSrinivas Kandagatla 			*p-- = 0;
115269aba794SSrinivas Kandagatla 	}
115369aba794SSrinivas Kandagatla 	/* clear msb bits if any leftover in the last byte */
115469aba794SSrinivas Kandagatla 	*p &= GENMASK((cell->nbits%BITS_PER_BYTE) - 1, 0);
115569aba794SSrinivas Kandagatla }
115669aba794SSrinivas Kandagatla 
115769aba794SSrinivas Kandagatla static int __nvmem_cell_read(struct nvmem_device *nvmem,
115869aba794SSrinivas Kandagatla 		      struct nvmem_cell *cell,
115969aba794SSrinivas Kandagatla 		      void *buf, size_t *len)
116069aba794SSrinivas Kandagatla {
116169aba794SSrinivas Kandagatla 	int rc;
116269aba794SSrinivas Kandagatla 
1163795ddd18SSrinivas Kandagatla 	rc = nvmem_reg_read(nvmem, cell->offset, buf, cell->bytes);
116469aba794SSrinivas Kandagatla 
1165287980e4SArnd Bergmann 	if (rc)
116669aba794SSrinivas Kandagatla 		return rc;
116769aba794SSrinivas Kandagatla 
116869aba794SSrinivas Kandagatla 	/* shift bits in-place */
1169cbf854abSAxel Lin 	if (cell->bit_offset || cell->nbits)
117069aba794SSrinivas Kandagatla 		nvmem_shift_read_buffer_in_place(cell, buf);
117169aba794SSrinivas Kandagatla 
11723b4a6877SVivek Gautam 	if (len)
117369aba794SSrinivas Kandagatla 		*len = cell->bytes;
117469aba794SSrinivas Kandagatla 
117569aba794SSrinivas Kandagatla 	return 0;
117669aba794SSrinivas Kandagatla }
117769aba794SSrinivas Kandagatla 
117869aba794SSrinivas Kandagatla /**
117969aba794SSrinivas Kandagatla  * nvmem_cell_read() - Read a given nvmem cell
118069aba794SSrinivas Kandagatla  *
118169aba794SSrinivas Kandagatla  * @cell: nvmem cell to be read.
11823b4a6877SVivek Gautam  * @len: pointer to length of cell which will be populated on successful read;
11833b4a6877SVivek Gautam  *	 can be NULL.
118469aba794SSrinivas Kandagatla  *
1185b577fafcSBrian Norris  * Return: ERR_PTR() on error or a valid pointer to a buffer on success. The
1186b577fafcSBrian Norris  * buffer should be freed by the consumer with a kfree().
118769aba794SSrinivas Kandagatla  */
118869aba794SSrinivas Kandagatla void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len)
118969aba794SSrinivas Kandagatla {
119069aba794SSrinivas Kandagatla 	struct nvmem_device *nvmem = cell->nvmem;
119169aba794SSrinivas Kandagatla 	u8 *buf;
119269aba794SSrinivas Kandagatla 	int rc;
119369aba794SSrinivas Kandagatla 
1194795ddd18SSrinivas Kandagatla 	if (!nvmem)
119569aba794SSrinivas Kandagatla 		return ERR_PTR(-EINVAL);
119669aba794SSrinivas Kandagatla 
119769aba794SSrinivas Kandagatla 	buf = kzalloc(cell->bytes, GFP_KERNEL);
119869aba794SSrinivas Kandagatla 	if (!buf)
119969aba794SSrinivas Kandagatla 		return ERR_PTR(-ENOMEM);
120069aba794SSrinivas Kandagatla 
120169aba794SSrinivas Kandagatla 	rc = __nvmem_cell_read(nvmem, cell, buf, len);
1202287980e4SArnd Bergmann 	if (rc) {
120369aba794SSrinivas Kandagatla 		kfree(buf);
120469aba794SSrinivas Kandagatla 		return ERR_PTR(rc);
120569aba794SSrinivas Kandagatla 	}
120669aba794SSrinivas Kandagatla 
120769aba794SSrinivas Kandagatla 	return buf;
120869aba794SSrinivas Kandagatla }
120969aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_read);
121069aba794SSrinivas Kandagatla 
1211f7c04f16SMasahiro Yamada static void *nvmem_cell_prepare_write_buffer(struct nvmem_cell *cell,
121269aba794SSrinivas Kandagatla 					     u8 *_buf, int len)
121369aba794SSrinivas Kandagatla {
121469aba794SSrinivas Kandagatla 	struct nvmem_device *nvmem = cell->nvmem;
121569aba794SSrinivas Kandagatla 	int i, rc, nbits, bit_offset = cell->bit_offset;
121669aba794SSrinivas Kandagatla 	u8 v, *p, *buf, *b, pbyte, pbits;
121769aba794SSrinivas Kandagatla 
121869aba794SSrinivas Kandagatla 	nbits = cell->nbits;
121969aba794SSrinivas Kandagatla 	buf = kzalloc(cell->bytes, GFP_KERNEL);
122069aba794SSrinivas Kandagatla 	if (!buf)
122169aba794SSrinivas Kandagatla 		return ERR_PTR(-ENOMEM);
122269aba794SSrinivas Kandagatla 
122369aba794SSrinivas Kandagatla 	memcpy(buf, _buf, len);
122469aba794SSrinivas Kandagatla 	p = b = buf;
122569aba794SSrinivas Kandagatla 
122669aba794SSrinivas Kandagatla 	if (bit_offset) {
122769aba794SSrinivas Kandagatla 		pbyte = *b;
122869aba794SSrinivas Kandagatla 		*b <<= bit_offset;
122969aba794SSrinivas Kandagatla 
123069aba794SSrinivas Kandagatla 		/* setup the first byte with lsb bits from nvmem */
1231795ddd18SSrinivas Kandagatla 		rc = nvmem_reg_read(nvmem, cell->offset, &v, 1);
123250808bfcSMathieu Malaterre 		if (rc)
123350808bfcSMathieu Malaterre 			goto err;
123469aba794SSrinivas Kandagatla 		*b++ |= GENMASK(bit_offset - 1, 0) & v;
123569aba794SSrinivas Kandagatla 
123669aba794SSrinivas Kandagatla 		/* setup rest of the byte if any */
123769aba794SSrinivas Kandagatla 		for (i = 1; i < cell->bytes; i++) {
123869aba794SSrinivas Kandagatla 			/* Get last byte bits and shift them towards lsb */
123969aba794SSrinivas Kandagatla 			pbits = pbyte >> (BITS_PER_BYTE - 1 - bit_offset);
124069aba794SSrinivas Kandagatla 			pbyte = *b;
124169aba794SSrinivas Kandagatla 			p = b;
124269aba794SSrinivas Kandagatla 			*b <<= bit_offset;
124369aba794SSrinivas Kandagatla 			*b++ |= pbits;
124469aba794SSrinivas Kandagatla 		}
124569aba794SSrinivas Kandagatla 	}
124669aba794SSrinivas Kandagatla 
124769aba794SSrinivas Kandagatla 	/* if it's not end on byte boundary */
124869aba794SSrinivas Kandagatla 	if ((nbits + bit_offset) % BITS_PER_BYTE) {
124969aba794SSrinivas Kandagatla 		/* setup the last byte with msb bits from nvmem */
1250795ddd18SSrinivas Kandagatla 		rc = nvmem_reg_read(nvmem,
125169aba794SSrinivas Kandagatla 				    cell->offset + cell->bytes - 1, &v, 1);
125250808bfcSMathieu Malaterre 		if (rc)
125350808bfcSMathieu Malaterre 			goto err;
125469aba794SSrinivas Kandagatla 		*p |= GENMASK(7, (nbits + bit_offset) % BITS_PER_BYTE) & v;
125569aba794SSrinivas Kandagatla 
125669aba794SSrinivas Kandagatla 	}
125769aba794SSrinivas Kandagatla 
125869aba794SSrinivas Kandagatla 	return buf;
125950808bfcSMathieu Malaterre err:
126050808bfcSMathieu Malaterre 	kfree(buf);
126150808bfcSMathieu Malaterre 	return ERR_PTR(rc);
126269aba794SSrinivas Kandagatla }
126369aba794SSrinivas Kandagatla 
126469aba794SSrinivas Kandagatla /**
126569aba794SSrinivas Kandagatla  * nvmem_cell_write() - Write to a given nvmem cell
126669aba794SSrinivas Kandagatla  *
126769aba794SSrinivas Kandagatla  * @cell: nvmem cell to be written.
126869aba794SSrinivas Kandagatla  * @buf: Buffer to be written.
126969aba794SSrinivas Kandagatla  * @len: length of buffer to be written to nvmem cell.
127069aba794SSrinivas Kandagatla  *
127169aba794SSrinivas Kandagatla  * Return: length of bytes written or negative on failure.
127269aba794SSrinivas Kandagatla  */
127369aba794SSrinivas Kandagatla int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len)
127469aba794SSrinivas Kandagatla {
127569aba794SSrinivas Kandagatla 	struct nvmem_device *nvmem = cell->nvmem;
127669aba794SSrinivas Kandagatla 	int rc;
127769aba794SSrinivas Kandagatla 
1278795ddd18SSrinivas Kandagatla 	if (!nvmem || nvmem->read_only ||
127969aba794SSrinivas Kandagatla 	    (cell->bit_offset == 0 && len != cell->bytes))
128069aba794SSrinivas Kandagatla 		return -EINVAL;
128169aba794SSrinivas Kandagatla 
128269aba794SSrinivas Kandagatla 	if (cell->bit_offset || cell->nbits) {
128369aba794SSrinivas Kandagatla 		buf = nvmem_cell_prepare_write_buffer(cell, buf, len);
128469aba794SSrinivas Kandagatla 		if (IS_ERR(buf))
128569aba794SSrinivas Kandagatla 			return PTR_ERR(buf);
128669aba794SSrinivas Kandagatla 	}
128769aba794SSrinivas Kandagatla 
1288795ddd18SSrinivas Kandagatla 	rc = nvmem_reg_write(nvmem, cell->offset, buf, cell->bytes);
128969aba794SSrinivas Kandagatla 
129069aba794SSrinivas Kandagatla 	/* free the tmp buffer */
1291ace22170SAxel Lin 	if (cell->bit_offset || cell->nbits)
129269aba794SSrinivas Kandagatla 		kfree(buf);
129369aba794SSrinivas Kandagatla 
1294287980e4SArnd Bergmann 	if (rc)
129569aba794SSrinivas Kandagatla 		return rc;
129669aba794SSrinivas Kandagatla 
129769aba794SSrinivas Kandagatla 	return len;
129869aba794SSrinivas Kandagatla }
129969aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_write);
130069aba794SSrinivas Kandagatla 
1301e2a5402eSSrinivas Kandagatla /**
1302d026d70aSLeonard Crestez  * nvmem_cell_read_u32() - Read a cell value as an u32
1303d026d70aSLeonard Crestez  *
1304d026d70aSLeonard Crestez  * @dev: Device that requests the nvmem cell.
1305d026d70aSLeonard Crestez  * @cell_id: Name of nvmem cell to read.
1306d026d70aSLeonard Crestez  * @val: pointer to output value.
1307d026d70aSLeonard Crestez  *
1308d026d70aSLeonard Crestez  * Return: 0 on success or negative errno.
1309d026d70aSLeonard Crestez  */
1310d026d70aSLeonard Crestez int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val)
1311d026d70aSLeonard Crestez {
1312d026d70aSLeonard Crestez 	struct nvmem_cell *cell;
1313d026d70aSLeonard Crestez 	void *buf;
1314d026d70aSLeonard Crestez 	size_t len;
1315d026d70aSLeonard Crestez 
1316d026d70aSLeonard Crestez 	cell = nvmem_cell_get(dev, cell_id);
1317d026d70aSLeonard Crestez 	if (IS_ERR(cell))
1318d026d70aSLeonard Crestez 		return PTR_ERR(cell);
1319d026d70aSLeonard Crestez 
1320d026d70aSLeonard Crestez 	buf = nvmem_cell_read(cell, &len);
1321d026d70aSLeonard Crestez 	if (IS_ERR(buf)) {
1322d026d70aSLeonard Crestez 		nvmem_cell_put(cell);
1323d026d70aSLeonard Crestez 		return PTR_ERR(buf);
1324d026d70aSLeonard Crestez 	}
1325d026d70aSLeonard Crestez 	if (len != sizeof(*val)) {
1326d026d70aSLeonard Crestez 		kfree(buf);
1327d026d70aSLeonard Crestez 		nvmem_cell_put(cell);
1328d026d70aSLeonard Crestez 		return -EINVAL;
1329d026d70aSLeonard Crestez 	}
1330d026d70aSLeonard Crestez 	memcpy(val, buf, sizeof(*val));
1331d026d70aSLeonard Crestez 
1332d026d70aSLeonard Crestez 	kfree(buf);
1333d026d70aSLeonard Crestez 	nvmem_cell_put(cell);
1334d026d70aSLeonard Crestez 	return 0;
1335d026d70aSLeonard Crestez }
1336d026d70aSLeonard Crestez EXPORT_SYMBOL_GPL(nvmem_cell_read_u32);
1337d026d70aSLeonard Crestez 
1338d026d70aSLeonard Crestez /**
1339e2a5402eSSrinivas Kandagatla  * nvmem_device_cell_read() - Read a given nvmem device and cell
1340e2a5402eSSrinivas Kandagatla  *
1341e2a5402eSSrinivas Kandagatla  * @nvmem: nvmem device to read from.
1342e2a5402eSSrinivas Kandagatla  * @info: nvmem cell info to be read.
1343e2a5402eSSrinivas Kandagatla  * @buf: buffer pointer which will be populated on successful read.
1344e2a5402eSSrinivas Kandagatla  *
1345e2a5402eSSrinivas Kandagatla  * Return: length of successful bytes read on success and negative
1346e2a5402eSSrinivas Kandagatla  * error code on error.
1347e2a5402eSSrinivas Kandagatla  */
1348e2a5402eSSrinivas Kandagatla ssize_t nvmem_device_cell_read(struct nvmem_device *nvmem,
1349e2a5402eSSrinivas Kandagatla 			   struct nvmem_cell_info *info, void *buf)
1350e2a5402eSSrinivas Kandagatla {
1351e2a5402eSSrinivas Kandagatla 	struct nvmem_cell cell;
1352e2a5402eSSrinivas Kandagatla 	int rc;
1353e2a5402eSSrinivas Kandagatla 	ssize_t len;
1354e2a5402eSSrinivas Kandagatla 
1355795ddd18SSrinivas Kandagatla 	if (!nvmem)
1356e2a5402eSSrinivas Kandagatla 		return -EINVAL;
1357e2a5402eSSrinivas Kandagatla 
1358e2a5402eSSrinivas Kandagatla 	rc = nvmem_cell_info_to_nvmem_cell(nvmem, info, &cell);
1359287980e4SArnd Bergmann 	if (rc)
1360e2a5402eSSrinivas Kandagatla 		return rc;
1361e2a5402eSSrinivas Kandagatla 
1362e2a5402eSSrinivas Kandagatla 	rc = __nvmem_cell_read(nvmem, &cell, buf, &len);
1363287980e4SArnd Bergmann 	if (rc)
1364e2a5402eSSrinivas Kandagatla 		return rc;
1365e2a5402eSSrinivas Kandagatla 
1366e2a5402eSSrinivas Kandagatla 	return len;
1367e2a5402eSSrinivas Kandagatla }
1368e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_cell_read);
1369e2a5402eSSrinivas Kandagatla 
1370e2a5402eSSrinivas Kandagatla /**
1371e2a5402eSSrinivas Kandagatla  * nvmem_device_cell_write() - Write cell to a given nvmem device
1372e2a5402eSSrinivas Kandagatla  *
1373e2a5402eSSrinivas Kandagatla  * @nvmem: nvmem device to be written to.
137429143268SVivek Gautam  * @info: nvmem cell info to be written.
1375e2a5402eSSrinivas Kandagatla  * @buf: buffer to be written to cell.
1376e2a5402eSSrinivas Kandagatla  *
1377e2a5402eSSrinivas Kandagatla  * Return: length of bytes written or negative error code on failure.
137848f63a2cSBartosz Golaszewski  */
1379e2a5402eSSrinivas Kandagatla int nvmem_device_cell_write(struct nvmem_device *nvmem,
1380e2a5402eSSrinivas Kandagatla 			    struct nvmem_cell_info *info, void *buf)
1381e2a5402eSSrinivas Kandagatla {
1382e2a5402eSSrinivas Kandagatla 	struct nvmem_cell cell;
1383e2a5402eSSrinivas Kandagatla 	int rc;
1384e2a5402eSSrinivas Kandagatla 
1385795ddd18SSrinivas Kandagatla 	if (!nvmem)
1386e2a5402eSSrinivas Kandagatla 		return -EINVAL;
1387e2a5402eSSrinivas Kandagatla 
1388e2a5402eSSrinivas Kandagatla 	rc = nvmem_cell_info_to_nvmem_cell(nvmem, info, &cell);
1389287980e4SArnd Bergmann 	if (rc)
1390e2a5402eSSrinivas Kandagatla 		return rc;
1391e2a5402eSSrinivas Kandagatla 
1392e2a5402eSSrinivas Kandagatla 	return nvmem_cell_write(&cell, buf, cell.bytes);
1393e2a5402eSSrinivas Kandagatla }
1394e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_cell_write);
1395e2a5402eSSrinivas Kandagatla 
1396e2a5402eSSrinivas Kandagatla /**
1397e2a5402eSSrinivas Kandagatla  * nvmem_device_read() - Read from a given nvmem device
1398e2a5402eSSrinivas Kandagatla  *
1399e2a5402eSSrinivas Kandagatla  * @nvmem: nvmem device to read from.
1400e2a5402eSSrinivas Kandagatla  * @offset: offset in nvmem device.
1401e2a5402eSSrinivas Kandagatla  * @bytes: number of bytes to read.
1402e2a5402eSSrinivas Kandagatla  * @buf: buffer pointer which will be populated on successful read.
1403e2a5402eSSrinivas Kandagatla  *
1404e2a5402eSSrinivas Kandagatla  * Return: length of successful bytes read on success and negative
1405e2a5402eSSrinivas Kandagatla  * error code on error.
1406e2a5402eSSrinivas Kandagatla  */
1407e2a5402eSSrinivas Kandagatla int nvmem_device_read(struct nvmem_device *nvmem,
1408e2a5402eSSrinivas Kandagatla 		      unsigned int offset,
1409e2a5402eSSrinivas Kandagatla 		      size_t bytes, void *buf)
1410e2a5402eSSrinivas Kandagatla {
1411e2a5402eSSrinivas Kandagatla 	int rc;
1412e2a5402eSSrinivas Kandagatla 
1413795ddd18SSrinivas Kandagatla 	if (!nvmem)
1414e2a5402eSSrinivas Kandagatla 		return -EINVAL;
1415e2a5402eSSrinivas Kandagatla 
1416795ddd18SSrinivas Kandagatla 	rc = nvmem_reg_read(nvmem, offset, buf, bytes);
1417e2a5402eSSrinivas Kandagatla 
1418287980e4SArnd Bergmann 	if (rc)
1419e2a5402eSSrinivas Kandagatla 		return rc;
1420e2a5402eSSrinivas Kandagatla 
1421e2a5402eSSrinivas Kandagatla 	return bytes;
1422e2a5402eSSrinivas Kandagatla }
1423e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_read);
1424e2a5402eSSrinivas Kandagatla 
1425e2a5402eSSrinivas Kandagatla /**
1426e2a5402eSSrinivas Kandagatla  * nvmem_device_write() - Write cell to a given nvmem device
1427e2a5402eSSrinivas Kandagatla  *
1428e2a5402eSSrinivas Kandagatla  * @nvmem: nvmem device to be written to.
1429e2a5402eSSrinivas Kandagatla  * @offset: offset in nvmem device.
1430e2a5402eSSrinivas Kandagatla  * @bytes: number of bytes to write.
1431e2a5402eSSrinivas Kandagatla  * @buf: buffer to be written.
1432e2a5402eSSrinivas Kandagatla  *
1433e2a5402eSSrinivas Kandagatla  * Return: length of bytes written or negative error code on failure.
143448f63a2cSBartosz Golaszewski  */
1435e2a5402eSSrinivas Kandagatla int nvmem_device_write(struct nvmem_device *nvmem,
1436e2a5402eSSrinivas Kandagatla 		       unsigned int offset,
1437e2a5402eSSrinivas Kandagatla 		       size_t bytes, void *buf)
1438e2a5402eSSrinivas Kandagatla {
1439e2a5402eSSrinivas Kandagatla 	int rc;
1440e2a5402eSSrinivas Kandagatla 
1441795ddd18SSrinivas Kandagatla 	if (!nvmem)
1442e2a5402eSSrinivas Kandagatla 		return -EINVAL;
1443e2a5402eSSrinivas Kandagatla 
1444795ddd18SSrinivas Kandagatla 	rc = nvmem_reg_write(nvmem, offset, buf, bytes);
1445e2a5402eSSrinivas Kandagatla 
1446287980e4SArnd Bergmann 	if (rc)
1447e2a5402eSSrinivas Kandagatla 		return rc;
1448e2a5402eSSrinivas Kandagatla 
1449e2a5402eSSrinivas Kandagatla 
1450e2a5402eSSrinivas Kandagatla 	return bytes;
1451e2a5402eSSrinivas Kandagatla }
1452e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_write);
1453e2a5402eSSrinivas Kandagatla 
1454d7b9fd16SBartosz Golaszewski /**
1455b985f4cbSBartosz Golaszewski  * nvmem_add_cell_table() - register a table of cell info entries
1456b985f4cbSBartosz Golaszewski  *
1457b985f4cbSBartosz Golaszewski  * @table: table of cell info entries
1458b985f4cbSBartosz Golaszewski  */
1459b985f4cbSBartosz Golaszewski void nvmem_add_cell_table(struct nvmem_cell_table *table)
1460b985f4cbSBartosz Golaszewski {
1461b985f4cbSBartosz Golaszewski 	mutex_lock(&nvmem_cell_mutex);
1462b985f4cbSBartosz Golaszewski 	list_add_tail(&table->node, &nvmem_cell_tables);
1463b985f4cbSBartosz Golaszewski 	mutex_unlock(&nvmem_cell_mutex);
1464b985f4cbSBartosz Golaszewski }
1465b985f4cbSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_add_cell_table);
1466b985f4cbSBartosz Golaszewski 
1467b985f4cbSBartosz Golaszewski /**
1468b985f4cbSBartosz Golaszewski  * nvmem_del_cell_table() - remove a previously registered cell info table
1469b985f4cbSBartosz Golaszewski  *
1470b985f4cbSBartosz Golaszewski  * @table: table of cell info entries
1471b985f4cbSBartosz Golaszewski  */
1472b985f4cbSBartosz Golaszewski void nvmem_del_cell_table(struct nvmem_cell_table *table)
1473b985f4cbSBartosz Golaszewski {
1474b985f4cbSBartosz Golaszewski 	mutex_lock(&nvmem_cell_mutex);
1475b985f4cbSBartosz Golaszewski 	list_del(&table->node);
1476b985f4cbSBartosz Golaszewski 	mutex_unlock(&nvmem_cell_mutex);
1477b985f4cbSBartosz Golaszewski }
1478b985f4cbSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_del_cell_table);
1479b985f4cbSBartosz Golaszewski 
1480b985f4cbSBartosz Golaszewski /**
1481506157beSBartosz Golaszewski  * nvmem_add_cell_lookups() - register a list of cell lookup entries
1482506157beSBartosz Golaszewski  *
1483506157beSBartosz Golaszewski  * @entries: array of cell lookup entries
1484506157beSBartosz Golaszewski  * @nentries: number of cell lookup entries in the array
1485506157beSBartosz Golaszewski  */
1486506157beSBartosz Golaszewski void nvmem_add_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries)
1487506157beSBartosz Golaszewski {
1488506157beSBartosz Golaszewski 	int i;
1489506157beSBartosz Golaszewski 
1490506157beSBartosz Golaszewski 	mutex_lock(&nvmem_lookup_mutex);
1491506157beSBartosz Golaszewski 	for (i = 0; i < nentries; i++)
1492506157beSBartosz Golaszewski 		list_add_tail(&entries[i].node, &nvmem_lookup_list);
1493506157beSBartosz Golaszewski 	mutex_unlock(&nvmem_lookup_mutex);
1494506157beSBartosz Golaszewski }
1495506157beSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_add_cell_lookups);
1496506157beSBartosz Golaszewski 
1497506157beSBartosz Golaszewski /**
1498506157beSBartosz Golaszewski  * nvmem_del_cell_lookups() - remove a list of previously added cell lookup
1499506157beSBartosz Golaszewski  *                            entries
1500506157beSBartosz Golaszewski  *
1501506157beSBartosz Golaszewski  * @entries: array of cell lookup entries
1502506157beSBartosz Golaszewski  * @nentries: number of cell lookup entries in the array
1503506157beSBartosz Golaszewski  */
1504506157beSBartosz Golaszewski void nvmem_del_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries)
1505506157beSBartosz Golaszewski {
1506506157beSBartosz Golaszewski 	int i;
1507506157beSBartosz Golaszewski 
1508506157beSBartosz Golaszewski 	mutex_lock(&nvmem_lookup_mutex);
1509506157beSBartosz Golaszewski 	for (i = 0; i < nentries; i++)
1510506157beSBartosz Golaszewski 		list_del(&entries[i].node);
1511506157beSBartosz Golaszewski 	mutex_unlock(&nvmem_lookup_mutex);
1512506157beSBartosz Golaszewski }
1513506157beSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_del_cell_lookups);
1514506157beSBartosz Golaszewski 
1515506157beSBartosz Golaszewski /**
1516d7b9fd16SBartosz Golaszewski  * nvmem_dev_name() - Get the name of a given nvmem device.
1517d7b9fd16SBartosz Golaszewski  *
1518d7b9fd16SBartosz Golaszewski  * @nvmem: nvmem device.
1519d7b9fd16SBartosz Golaszewski  *
1520d7b9fd16SBartosz Golaszewski  * Return: name of the nvmem device.
1521d7b9fd16SBartosz Golaszewski  */
1522d7b9fd16SBartosz Golaszewski const char *nvmem_dev_name(struct nvmem_device *nvmem)
1523d7b9fd16SBartosz Golaszewski {
1524d7b9fd16SBartosz Golaszewski 	return dev_name(&nvmem->dev);
1525d7b9fd16SBartosz Golaszewski }
1526d7b9fd16SBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_dev_name);
1527d7b9fd16SBartosz Golaszewski 
1528eace75cfSSrinivas Kandagatla static int __init nvmem_init(void)
1529eace75cfSSrinivas Kandagatla {
1530eace75cfSSrinivas Kandagatla 	return bus_register(&nvmem_bus_type);
1531eace75cfSSrinivas Kandagatla }
1532eace75cfSSrinivas Kandagatla 
1533eace75cfSSrinivas Kandagatla static void __exit nvmem_exit(void)
1534eace75cfSSrinivas Kandagatla {
1535eace75cfSSrinivas Kandagatla 	bus_unregister(&nvmem_bus_type);
1536eace75cfSSrinivas Kandagatla }
1537eace75cfSSrinivas Kandagatla 
1538eace75cfSSrinivas Kandagatla subsys_initcall(nvmem_init);
1539eace75cfSSrinivas Kandagatla module_exit(nvmem_exit);
1540eace75cfSSrinivas Kandagatla 
1541eace75cfSSrinivas Kandagatla MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org");
1542eace75cfSSrinivas Kandagatla MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com");
1543eace75cfSSrinivas Kandagatla MODULE_DESCRIPTION("nvmem Driver Core");
1544eace75cfSSrinivas Kandagatla MODULE_LICENSE("GPL v2");
1545