xref: /linux/drivers/nvmem/core.c (revision a8b44d5d2e38e94e4c20a3fba294c3375753b469)
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;
3116688453SAlexandre Belloni 	enum nvmem_type		type;
32b6c217abSAndrew Lunn 	struct bin_attribute	eeprom;
33b6c217abSAndrew Lunn 	struct device		*base_dev;
34c7235ee3SBartosz Golaszewski 	struct list_head	cells;
35795ddd18SSrinivas Kandagatla 	nvmem_reg_read_t	reg_read;
36795ddd18SSrinivas Kandagatla 	nvmem_reg_write_t	reg_write;
37795ddd18SSrinivas Kandagatla 	void *priv;
38eace75cfSSrinivas Kandagatla };
39eace75cfSSrinivas Kandagatla 
40b6c217abSAndrew Lunn #define FLAG_COMPAT		BIT(0)
41b6c217abSAndrew Lunn 
42eace75cfSSrinivas Kandagatla struct nvmem_cell {
43eace75cfSSrinivas Kandagatla 	const char		*name;
44eace75cfSSrinivas Kandagatla 	int			offset;
45eace75cfSSrinivas Kandagatla 	int			bytes;
46eace75cfSSrinivas Kandagatla 	int			bit_offset;
47eace75cfSSrinivas Kandagatla 	int			nbits;
480749aa25SSrinivas Kandagatla 	struct device_node	*np;
49eace75cfSSrinivas Kandagatla 	struct nvmem_device	*nvmem;
50eace75cfSSrinivas Kandagatla 	struct list_head	node;
51eace75cfSSrinivas Kandagatla };
52eace75cfSSrinivas Kandagatla 
53eace75cfSSrinivas Kandagatla static DEFINE_MUTEX(nvmem_mutex);
54eace75cfSSrinivas Kandagatla static DEFINE_IDA(nvmem_ida);
55eace75cfSSrinivas Kandagatla 
56b985f4cbSBartosz Golaszewski static DEFINE_MUTEX(nvmem_cell_mutex);
57b985f4cbSBartosz Golaszewski static LIST_HEAD(nvmem_cell_tables);
58b985f4cbSBartosz Golaszewski 
59506157beSBartosz Golaszewski static DEFINE_MUTEX(nvmem_lookup_mutex);
60506157beSBartosz Golaszewski static LIST_HEAD(nvmem_lookup_list);
61506157beSBartosz Golaszewski 
62bee1138bSBartosz Golaszewski static BLOCKING_NOTIFIER_HEAD(nvmem_notifier);
63bee1138bSBartosz Golaszewski 
64*a8b44d5dSAndy Shevchenko static const char * const nvmem_type_str[] = {
65*a8b44d5dSAndy Shevchenko 	[NVMEM_TYPE_UNKNOWN] = "Unknown",
66*a8b44d5dSAndy Shevchenko 	[NVMEM_TYPE_EEPROM] = "EEPROM",
67*a8b44d5dSAndy Shevchenko 	[NVMEM_TYPE_OTP] = "OTP",
68*a8b44d5dSAndy Shevchenko 	[NVMEM_TYPE_BATTERY_BACKED] = "Battery backed",
69*a8b44d5dSAndy Shevchenko };
70*a8b44d5dSAndy Shevchenko 
71b6c217abSAndrew Lunn #ifdef CONFIG_DEBUG_LOCK_ALLOC
72b6c217abSAndrew Lunn static struct lock_class_key eeprom_lock_key;
73b6c217abSAndrew Lunn #endif
74b6c217abSAndrew Lunn 
75eace75cfSSrinivas Kandagatla #define to_nvmem_device(d) container_of(d, struct nvmem_device, dev)
76795ddd18SSrinivas Kandagatla static int nvmem_reg_read(struct nvmem_device *nvmem, unsigned int offset,
77795ddd18SSrinivas Kandagatla 			  void *val, size_t bytes)
78795ddd18SSrinivas Kandagatla {
79795ddd18SSrinivas Kandagatla 	if (nvmem->reg_read)
80795ddd18SSrinivas Kandagatla 		return nvmem->reg_read(nvmem->priv, offset, val, bytes);
81795ddd18SSrinivas Kandagatla 
82795ddd18SSrinivas Kandagatla 	return -EINVAL;
83795ddd18SSrinivas Kandagatla }
84795ddd18SSrinivas Kandagatla 
85795ddd18SSrinivas Kandagatla static int nvmem_reg_write(struct nvmem_device *nvmem, unsigned int offset,
86795ddd18SSrinivas Kandagatla 			   void *val, size_t bytes)
87795ddd18SSrinivas Kandagatla {
88795ddd18SSrinivas Kandagatla 	if (nvmem->reg_write)
89795ddd18SSrinivas Kandagatla 		return nvmem->reg_write(nvmem->priv, offset, val, bytes);
90795ddd18SSrinivas Kandagatla 
91795ddd18SSrinivas Kandagatla 	return -EINVAL;
92795ddd18SSrinivas Kandagatla }
93eace75cfSSrinivas Kandagatla 
9416688453SAlexandre Belloni static ssize_t type_show(struct device *dev,
9516688453SAlexandre Belloni 			 struct device_attribute *attr, char *buf)
9616688453SAlexandre Belloni {
9716688453SAlexandre Belloni 	struct nvmem_device *nvmem = to_nvmem_device(dev);
9816688453SAlexandre Belloni 
9916688453SAlexandre Belloni 	return sprintf(buf, "%s\n", nvmem_type_str[nvmem->type]);
10016688453SAlexandre Belloni }
10116688453SAlexandre Belloni 
10216688453SAlexandre Belloni static DEVICE_ATTR_RO(type);
10316688453SAlexandre Belloni 
10416688453SAlexandre Belloni static struct attribute *nvmem_attrs[] = {
10516688453SAlexandre Belloni 	&dev_attr_type.attr,
10616688453SAlexandre Belloni 	NULL,
10716688453SAlexandre Belloni };
10816688453SAlexandre Belloni 
109eace75cfSSrinivas Kandagatla static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj,
110eace75cfSSrinivas Kandagatla 				    struct bin_attribute *attr,
111eace75cfSSrinivas Kandagatla 				    char *buf, loff_t pos, size_t count)
112eace75cfSSrinivas Kandagatla {
113b6c217abSAndrew Lunn 	struct device *dev;
114b6c217abSAndrew Lunn 	struct nvmem_device *nvmem;
115eace75cfSSrinivas Kandagatla 	int rc;
116eace75cfSSrinivas Kandagatla 
117b6c217abSAndrew Lunn 	if (attr->private)
118b6c217abSAndrew Lunn 		dev = attr->private;
119b6c217abSAndrew Lunn 	else
120b6c217abSAndrew Lunn 		dev = container_of(kobj, struct device, kobj);
121b6c217abSAndrew Lunn 	nvmem = to_nvmem_device(dev);
122b6c217abSAndrew Lunn 
123eace75cfSSrinivas Kandagatla 	/* Stop the user from reading */
1247c806883SZhengShunQian 	if (pos >= nvmem->size)
125eace75cfSSrinivas Kandagatla 		return 0;
126eace75cfSSrinivas Kandagatla 
127313a72ffSSrinivas Kandagatla 	if (count < nvmem->word_size)
128313a72ffSSrinivas Kandagatla 		return -EINVAL;
129313a72ffSSrinivas Kandagatla 
130eace75cfSSrinivas Kandagatla 	if (pos + count > nvmem->size)
131eace75cfSSrinivas Kandagatla 		count = nvmem->size - pos;
132eace75cfSSrinivas Kandagatla 
133eace75cfSSrinivas Kandagatla 	count = round_down(count, nvmem->word_size);
134eace75cfSSrinivas Kandagatla 
135795ddd18SSrinivas Kandagatla 	rc = nvmem_reg_read(nvmem, pos, buf, count);
136eace75cfSSrinivas Kandagatla 
137287980e4SArnd Bergmann 	if (rc)
138eace75cfSSrinivas Kandagatla 		return rc;
139eace75cfSSrinivas Kandagatla 
140eace75cfSSrinivas Kandagatla 	return count;
141eace75cfSSrinivas Kandagatla }
142eace75cfSSrinivas Kandagatla 
143eace75cfSSrinivas Kandagatla static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj,
144eace75cfSSrinivas Kandagatla 				     struct bin_attribute *attr,
145eace75cfSSrinivas Kandagatla 				     char *buf, loff_t pos, size_t count)
146eace75cfSSrinivas Kandagatla {
147b6c217abSAndrew Lunn 	struct device *dev;
148b6c217abSAndrew Lunn 	struct nvmem_device *nvmem;
149eace75cfSSrinivas Kandagatla 	int rc;
150eace75cfSSrinivas Kandagatla 
151b6c217abSAndrew Lunn 	if (attr->private)
152b6c217abSAndrew Lunn 		dev = attr->private;
153b6c217abSAndrew Lunn 	else
154b6c217abSAndrew Lunn 		dev = container_of(kobj, struct device, kobj);
155b6c217abSAndrew Lunn 	nvmem = to_nvmem_device(dev);
156b6c217abSAndrew Lunn 
157eace75cfSSrinivas Kandagatla 	/* Stop the user from writing */
1587c806883SZhengShunQian 	if (pos >= nvmem->size)
15938b0774cSGuy Shapiro 		return -EFBIG;
160eace75cfSSrinivas Kandagatla 
161313a72ffSSrinivas Kandagatla 	if (count < nvmem->word_size)
162313a72ffSSrinivas Kandagatla 		return -EINVAL;
163313a72ffSSrinivas Kandagatla 
164eace75cfSSrinivas Kandagatla 	if (pos + count > nvmem->size)
165eace75cfSSrinivas Kandagatla 		count = nvmem->size - pos;
166eace75cfSSrinivas Kandagatla 
167eace75cfSSrinivas Kandagatla 	count = round_down(count, nvmem->word_size);
168eace75cfSSrinivas Kandagatla 
169795ddd18SSrinivas Kandagatla 	rc = nvmem_reg_write(nvmem, pos, buf, count);
170eace75cfSSrinivas Kandagatla 
171287980e4SArnd Bergmann 	if (rc)
172eace75cfSSrinivas Kandagatla 		return rc;
173eace75cfSSrinivas Kandagatla 
174eace75cfSSrinivas Kandagatla 	return count;
175eace75cfSSrinivas Kandagatla }
176eace75cfSSrinivas Kandagatla 
177eace75cfSSrinivas Kandagatla /* default read/write permissions */
178eace75cfSSrinivas Kandagatla static struct bin_attribute bin_attr_rw_nvmem = {
179eace75cfSSrinivas Kandagatla 	.attr	= {
180eace75cfSSrinivas Kandagatla 		.name	= "nvmem",
181e7e07f4fSBartosz Golaszewski 		.mode	= 0644,
182eace75cfSSrinivas Kandagatla 	},
183eace75cfSSrinivas Kandagatla 	.read	= bin_attr_nvmem_read,
184eace75cfSSrinivas Kandagatla 	.write	= bin_attr_nvmem_write,
185eace75cfSSrinivas Kandagatla };
186eace75cfSSrinivas Kandagatla 
187eace75cfSSrinivas Kandagatla static struct bin_attribute *nvmem_bin_rw_attributes[] = {
188eace75cfSSrinivas Kandagatla 	&bin_attr_rw_nvmem,
189eace75cfSSrinivas Kandagatla 	NULL,
190eace75cfSSrinivas Kandagatla };
191eace75cfSSrinivas Kandagatla 
192eace75cfSSrinivas Kandagatla static const struct attribute_group nvmem_bin_rw_group = {
193eace75cfSSrinivas Kandagatla 	.bin_attrs	= nvmem_bin_rw_attributes,
19416688453SAlexandre Belloni 	.attrs		= nvmem_attrs,
195eace75cfSSrinivas Kandagatla };
196eace75cfSSrinivas Kandagatla 
197eace75cfSSrinivas Kandagatla static const struct attribute_group *nvmem_rw_dev_groups[] = {
198eace75cfSSrinivas Kandagatla 	&nvmem_bin_rw_group,
199eace75cfSSrinivas Kandagatla 	NULL,
200eace75cfSSrinivas Kandagatla };
201eace75cfSSrinivas Kandagatla 
202eace75cfSSrinivas Kandagatla /* read only permission */
203eace75cfSSrinivas Kandagatla static struct bin_attribute bin_attr_ro_nvmem = {
204eace75cfSSrinivas Kandagatla 	.attr	= {
205eace75cfSSrinivas Kandagatla 		.name	= "nvmem",
206e7e07f4fSBartosz Golaszewski 		.mode	= 0444,
207eace75cfSSrinivas Kandagatla 	},
208eace75cfSSrinivas Kandagatla 	.read	= bin_attr_nvmem_read,
209eace75cfSSrinivas Kandagatla };
210eace75cfSSrinivas Kandagatla 
211eace75cfSSrinivas Kandagatla static struct bin_attribute *nvmem_bin_ro_attributes[] = {
212eace75cfSSrinivas Kandagatla 	&bin_attr_ro_nvmem,
213eace75cfSSrinivas Kandagatla 	NULL,
214eace75cfSSrinivas Kandagatla };
215eace75cfSSrinivas Kandagatla 
216eace75cfSSrinivas Kandagatla static const struct attribute_group nvmem_bin_ro_group = {
217eace75cfSSrinivas Kandagatla 	.bin_attrs	= nvmem_bin_ro_attributes,
21816688453SAlexandre Belloni 	.attrs		= nvmem_attrs,
219eace75cfSSrinivas Kandagatla };
220eace75cfSSrinivas Kandagatla 
221eace75cfSSrinivas Kandagatla static const struct attribute_group *nvmem_ro_dev_groups[] = {
222eace75cfSSrinivas Kandagatla 	&nvmem_bin_ro_group,
223eace75cfSSrinivas Kandagatla 	NULL,
224eace75cfSSrinivas Kandagatla };
225eace75cfSSrinivas Kandagatla 
226811b0d65SAndrew Lunn /* default read/write permissions, root only */
227811b0d65SAndrew Lunn static struct bin_attribute bin_attr_rw_root_nvmem = {
228811b0d65SAndrew Lunn 	.attr	= {
229811b0d65SAndrew Lunn 		.name	= "nvmem",
230e7e07f4fSBartosz Golaszewski 		.mode	= 0600,
231811b0d65SAndrew Lunn 	},
232811b0d65SAndrew Lunn 	.read	= bin_attr_nvmem_read,
233811b0d65SAndrew Lunn 	.write	= bin_attr_nvmem_write,
234811b0d65SAndrew Lunn };
235811b0d65SAndrew Lunn 
236811b0d65SAndrew Lunn static struct bin_attribute *nvmem_bin_rw_root_attributes[] = {
237811b0d65SAndrew Lunn 	&bin_attr_rw_root_nvmem,
238811b0d65SAndrew Lunn 	NULL,
239811b0d65SAndrew Lunn };
240811b0d65SAndrew Lunn 
241811b0d65SAndrew Lunn static const struct attribute_group nvmem_bin_rw_root_group = {
242811b0d65SAndrew Lunn 	.bin_attrs	= nvmem_bin_rw_root_attributes,
24316688453SAlexandre Belloni 	.attrs		= nvmem_attrs,
244811b0d65SAndrew Lunn };
245811b0d65SAndrew Lunn 
246811b0d65SAndrew Lunn static const struct attribute_group *nvmem_rw_root_dev_groups[] = {
247811b0d65SAndrew Lunn 	&nvmem_bin_rw_root_group,
248811b0d65SAndrew Lunn 	NULL,
249811b0d65SAndrew Lunn };
250811b0d65SAndrew Lunn 
251811b0d65SAndrew Lunn /* read only permission, root only */
252811b0d65SAndrew Lunn static struct bin_attribute bin_attr_ro_root_nvmem = {
253811b0d65SAndrew Lunn 	.attr	= {
254811b0d65SAndrew Lunn 		.name	= "nvmem",
255e7e07f4fSBartosz Golaszewski 		.mode	= 0400,
256811b0d65SAndrew Lunn 	},
257811b0d65SAndrew Lunn 	.read	= bin_attr_nvmem_read,
258811b0d65SAndrew Lunn };
259811b0d65SAndrew Lunn 
260811b0d65SAndrew Lunn static struct bin_attribute *nvmem_bin_ro_root_attributes[] = {
261811b0d65SAndrew Lunn 	&bin_attr_ro_root_nvmem,
262811b0d65SAndrew Lunn 	NULL,
263811b0d65SAndrew Lunn };
264811b0d65SAndrew Lunn 
265811b0d65SAndrew Lunn static const struct attribute_group nvmem_bin_ro_root_group = {
266811b0d65SAndrew Lunn 	.bin_attrs	= nvmem_bin_ro_root_attributes,
26716688453SAlexandre Belloni 	.attrs		= nvmem_attrs,
268811b0d65SAndrew Lunn };
269811b0d65SAndrew Lunn 
270811b0d65SAndrew Lunn static const struct attribute_group *nvmem_ro_root_dev_groups[] = {
271811b0d65SAndrew Lunn 	&nvmem_bin_ro_root_group,
272811b0d65SAndrew Lunn 	NULL,
273811b0d65SAndrew Lunn };
274811b0d65SAndrew Lunn 
275eace75cfSSrinivas Kandagatla static void nvmem_release(struct device *dev)
276eace75cfSSrinivas Kandagatla {
277eace75cfSSrinivas Kandagatla 	struct nvmem_device *nvmem = to_nvmem_device(dev);
278eace75cfSSrinivas Kandagatla 
279eace75cfSSrinivas Kandagatla 	ida_simple_remove(&nvmem_ida, nvmem->id);
280eace75cfSSrinivas Kandagatla 	kfree(nvmem);
281eace75cfSSrinivas Kandagatla }
282eace75cfSSrinivas Kandagatla 
283eace75cfSSrinivas Kandagatla static const struct device_type nvmem_provider_type = {
284eace75cfSSrinivas Kandagatla 	.release	= nvmem_release,
285eace75cfSSrinivas Kandagatla };
286eace75cfSSrinivas Kandagatla 
287eace75cfSSrinivas Kandagatla static struct bus_type nvmem_bus_type = {
288eace75cfSSrinivas Kandagatla 	.name		= "nvmem",
289eace75cfSSrinivas Kandagatla };
290eace75cfSSrinivas Kandagatla 
291eace75cfSSrinivas Kandagatla static int of_nvmem_match(struct device *dev, void *nvmem_np)
292eace75cfSSrinivas Kandagatla {
293eace75cfSSrinivas Kandagatla 	return dev->of_node == nvmem_np;
294eace75cfSSrinivas Kandagatla }
295eace75cfSSrinivas Kandagatla 
296eace75cfSSrinivas Kandagatla static struct nvmem_device *of_nvmem_find(struct device_node *nvmem_np)
297eace75cfSSrinivas Kandagatla {
298eace75cfSSrinivas Kandagatla 	struct device *d;
299eace75cfSSrinivas Kandagatla 
300eace75cfSSrinivas Kandagatla 	if (!nvmem_np)
301eace75cfSSrinivas Kandagatla 		return NULL;
302eace75cfSSrinivas Kandagatla 
303eace75cfSSrinivas Kandagatla 	d = bus_find_device(&nvmem_bus_type, NULL, nvmem_np, of_nvmem_match);
304eace75cfSSrinivas Kandagatla 
305eace75cfSSrinivas Kandagatla 	if (!d)
306eace75cfSSrinivas Kandagatla 		return NULL;
307eace75cfSSrinivas Kandagatla 
308eace75cfSSrinivas Kandagatla 	return to_nvmem_device(d);
309eace75cfSSrinivas Kandagatla }
310eace75cfSSrinivas Kandagatla 
311506157beSBartosz Golaszewski static struct nvmem_device *nvmem_find(const char *name)
312506157beSBartosz Golaszewski {
313506157beSBartosz Golaszewski 	struct device *d;
314506157beSBartosz Golaszewski 
315506157beSBartosz Golaszewski 	d = bus_find_device_by_name(&nvmem_bus_type, NULL, name);
316506157beSBartosz Golaszewski 
317506157beSBartosz Golaszewski 	if (!d)
318506157beSBartosz Golaszewski 		return NULL;
319506157beSBartosz Golaszewski 
320506157beSBartosz Golaszewski 	return to_nvmem_device(d);
321506157beSBartosz Golaszewski }
322506157beSBartosz Golaszewski 
323eace75cfSSrinivas Kandagatla static void nvmem_cell_drop(struct nvmem_cell *cell)
324eace75cfSSrinivas Kandagatla {
325bee1138bSBartosz Golaszewski 	blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_REMOVE, cell);
326c7235ee3SBartosz Golaszewski 	mutex_lock(&nvmem_mutex);
327eace75cfSSrinivas Kandagatla 	list_del(&cell->node);
328c7235ee3SBartosz Golaszewski 	mutex_unlock(&nvmem_mutex);
3290749aa25SSrinivas Kandagatla 	of_node_put(cell->np);
330badcdff1SRob Herring 	kfree(cell->name);
331eace75cfSSrinivas Kandagatla 	kfree(cell);
332eace75cfSSrinivas Kandagatla }
333eace75cfSSrinivas Kandagatla 
334eace75cfSSrinivas Kandagatla static void nvmem_device_remove_all_cells(const struct nvmem_device *nvmem)
335eace75cfSSrinivas Kandagatla {
3361852183eSBartosz Golaszewski 	struct nvmem_cell *cell, *p;
337eace75cfSSrinivas Kandagatla 
338c7235ee3SBartosz Golaszewski 	list_for_each_entry_safe(cell, p, &nvmem->cells, node)
339eace75cfSSrinivas Kandagatla 		nvmem_cell_drop(cell);
340eace75cfSSrinivas Kandagatla }
341eace75cfSSrinivas Kandagatla 
342eace75cfSSrinivas Kandagatla static void nvmem_cell_add(struct nvmem_cell *cell)
343eace75cfSSrinivas Kandagatla {
344c7235ee3SBartosz Golaszewski 	mutex_lock(&nvmem_mutex);
345c7235ee3SBartosz Golaszewski 	list_add_tail(&cell->node, &cell->nvmem->cells);
346c7235ee3SBartosz Golaszewski 	mutex_unlock(&nvmem_mutex);
347bee1138bSBartosz Golaszewski 	blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_ADD, cell);
348eace75cfSSrinivas Kandagatla }
349eace75cfSSrinivas Kandagatla 
350eace75cfSSrinivas Kandagatla static int nvmem_cell_info_to_nvmem_cell(struct nvmem_device *nvmem,
351eace75cfSSrinivas Kandagatla 				   const struct nvmem_cell_info *info,
352eace75cfSSrinivas Kandagatla 				   struct nvmem_cell *cell)
353eace75cfSSrinivas Kandagatla {
354eace75cfSSrinivas Kandagatla 	cell->nvmem = nvmem;
355eace75cfSSrinivas Kandagatla 	cell->offset = info->offset;
356eace75cfSSrinivas Kandagatla 	cell->bytes = info->bytes;
357eace75cfSSrinivas Kandagatla 	cell->name = info->name;
358eace75cfSSrinivas Kandagatla 
359eace75cfSSrinivas Kandagatla 	cell->bit_offset = info->bit_offset;
360eace75cfSSrinivas Kandagatla 	cell->nbits = info->nbits;
361eace75cfSSrinivas Kandagatla 
362eace75cfSSrinivas Kandagatla 	if (cell->nbits)
363eace75cfSSrinivas Kandagatla 		cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset,
364eace75cfSSrinivas Kandagatla 					   BITS_PER_BYTE);
365eace75cfSSrinivas Kandagatla 
366eace75cfSSrinivas Kandagatla 	if (!IS_ALIGNED(cell->offset, nvmem->stride)) {
367eace75cfSSrinivas Kandagatla 		dev_err(&nvmem->dev,
368eace75cfSSrinivas Kandagatla 			"cell %s unaligned to nvmem stride %d\n",
369eace75cfSSrinivas Kandagatla 			cell->name, nvmem->stride);
370eace75cfSSrinivas Kandagatla 		return -EINVAL;
371eace75cfSSrinivas Kandagatla 	}
372eace75cfSSrinivas Kandagatla 
373eace75cfSSrinivas Kandagatla 	return 0;
374eace75cfSSrinivas Kandagatla }
375eace75cfSSrinivas Kandagatla 
376b3db17e4SAndrew Lunn /**
377b3db17e4SAndrew Lunn  * nvmem_add_cells() - Add cell information to an nvmem device
378b3db17e4SAndrew Lunn  *
379b3db17e4SAndrew Lunn  * @nvmem: nvmem device to add cells to.
380b3db17e4SAndrew Lunn  * @info: nvmem cell info to add to the device
381b3db17e4SAndrew Lunn  * @ncells: number of cells in info
382b3db17e4SAndrew Lunn  *
383b3db17e4SAndrew Lunn  * Return: 0 or negative error code on failure.
384b3db17e4SAndrew Lunn  */
385ef92ab30SSrinivas Kandagatla static int nvmem_add_cells(struct nvmem_device *nvmem,
386b3db17e4SAndrew Lunn 		    const struct nvmem_cell_info *info,
387b3db17e4SAndrew Lunn 		    int ncells)
388eace75cfSSrinivas Kandagatla {
389eace75cfSSrinivas Kandagatla 	struct nvmem_cell **cells;
390eace75cfSSrinivas Kandagatla 	int i, rval;
391eace75cfSSrinivas Kandagatla 
392b3db17e4SAndrew Lunn 	cells = kcalloc(ncells, sizeof(*cells), GFP_KERNEL);
393eace75cfSSrinivas Kandagatla 	if (!cells)
394eace75cfSSrinivas Kandagatla 		return -ENOMEM;
395eace75cfSSrinivas Kandagatla 
396b3db17e4SAndrew Lunn 	for (i = 0; i < ncells; i++) {
397eace75cfSSrinivas Kandagatla 		cells[i] = kzalloc(sizeof(**cells), GFP_KERNEL);
398eace75cfSSrinivas Kandagatla 		if (!cells[i]) {
399eace75cfSSrinivas Kandagatla 			rval = -ENOMEM;
400eace75cfSSrinivas Kandagatla 			goto err;
401eace75cfSSrinivas Kandagatla 		}
402eace75cfSSrinivas Kandagatla 
403eace75cfSSrinivas Kandagatla 		rval = nvmem_cell_info_to_nvmem_cell(nvmem, &info[i], cells[i]);
404287980e4SArnd Bergmann 		if (rval) {
405eace75cfSSrinivas Kandagatla 			kfree(cells[i]);
406eace75cfSSrinivas Kandagatla 			goto err;
407eace75cfSSrinivas Kandagatla 		}
408eace75cfSSrinivas Kandagatla 
409eace75cfSSrinivas Kandagatla 		nvmem_cell_add(cells[i]);
410eace75cfSSrinivas Kandagatla 	}
411eace75cfSSrinivas Kandagatla 
412eace75cfSSrinivas Kandagatla 	/* remove tmp array */
413eace75cfSSrinivas Kandagatla 	kfree(cells);
414eace75cfSSrinivas Kandagatla 
415eace75cfSSrinivas Kandagatla 	return 0;
416eace75cfSSrinivas Kandagatla err:
417dfdf1414SRasmus Villemoes 	while (i--)
418eace75cfSSrinivas Kandagatla 		nvmem_cell_drop(cells[i]);
419eace75cfSSrinivas Kandagatla 
420dfdf1414SRasmus Villemoes 	kfree(cells);
421dfdf1414SRasmus Villemoes 
422eace75cfSSrinivas Kandagatla 	return rval;
423eace75cfSSrinivas Kandagatla }
424eace75cfSSrinivas Kandagatla 
425b6c217abSAndrew Lunn /*
426b6c217abSAndrew Lunn  * nvmem_setup_compat() - Create an additional binary entry in
427b6c217abSAndrew Lunn  * drivers sys directory, to be backwards compatible with the older
428b6c217abSAndrew Lunn  * drivers/misc/eeprom drivers.
429b6c217abSAndrew Lunn  */
430b6c217abSAndrew Lunn static int nvmem_setup_compat(struct nvmem_device *nvmem,
431b6c217abSAndrew Lunn 			      const struct nvmem_config *config)
432b6c217abSAndrew Lunn {
433b6c217abSAndrew Lunn 	int rval;
434b6c217abSAndrew Lunn 
435b6c217abSAndrew Lunn 	if (!config->base_dev)
436b6c217abSAndrew Lunn 		return -EINVAL;
437b6c217abSAndrew Lunn 
438b6c217abSAndrew Lunn 	if (nvmem->read_only)
439b6c217abSAndrew Lunn 		nvmem->eeprom = bin_attr_ro_root_nvmem;
440b6c217abSAndrew Lunn 	else
441b6c217abSAndrew Lunn 		nvmem->eeprom = bin_attr_rw_root_nvmem;
442b6c217abSAndrew Lunn 	nvmem->eeprom.attr.name = "eeprom";
443b6c217abSAndrew Lunn 	nvmem->eeprom.size = nvmem->size;
444b6c217abSAndrew Lunn #ifdef CONFIG_DEBUG_LOCK_ALLOC
445b6c217abSAndrew Lunn 	nvmem->eeprom.attr.key = &eeprom_lock_key;
446b6c217abSAndrew Lunn #endif
447b6c217abSAndrew Lunn 	nvmem->eeprom.private = &nvmem->dev;
448b6c217abSAndrew Lunn 	nvmem->base_dev = config->base_dev;
449b6c217abSAndrew Lunn 
450b6c217abSAndrew Lunn 	rval = device_create_bin_file(nvmem->base_dev, &nvmem->eeprom);
451b6c217abSAndrew Lunn 	if (rval) {
452b6c217abSAndrew Lunn 		dev_err(&nvmem->dev,
453b6c217abSAndrew Lunn 			"Failed to create eeprom binary file %d\n", rval);
454b6c217abSAndrew Lunn 		return rval;
455b6c217abSAndrew Lunn 	}
456b6c217abSAndrew Lunn 
457b6c217abSAndrew Lunn 	nvmem->flags |= FLAG_COMPAT;
458b6c217abSAndrew Lunn 
459b6c217abSAndrew Lunn 	return 0;
460b6c217abSAndrew Lunn }
461b6c217abSAndrew Lunn 
462bee1138bSBartosz Golaszewski /**
463bee1138bSBartosz Golaszewski  * nvmem_register_notifier() - Register a notifier block for nvmem events.
464bee1138bSBartosz Golaszewski  *
465bee1138bSBartosz Golaszewski  * @nb: notifier block to be called on nvmem events.
466bee1138bSBartosz Golaszewski  *
467bee1138bSBartosz Golaszewski  * Return: 0 on success, negative error number on failure.
468bee1138bSBartosz Golaszewski  */
469bee1138bSBartosz Golaszewski int nvmem_register_notifier(struct notifier_block *nb)
470bee1138bSBartosz Golaszewski {
471bee1138bSBartosz Golaszewski 	return blocking_notifier_chain_register(&nvmem_notifier, nb);
472bee1138bSBartosz Golaszewski }
473bee1138bSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_register_notifier);
474bee1138bSBartosz Golaszewski 
475bee1138bSBartosz Golaszewski /**
476bee1138bSBartosz Golaszewski  * nvmem_unregister_notifier() - Unregister a notifier block for nvmem events.
477bee1138bSBartosz Golaszewski  *
478bee1138bSBartosz Golaszewski  * @nb: notifier block to be unregistered.
479bee1138bSBartosz Golaszewski  *
480bee1138bSBartosz Golaszewski  * Return: 0 on success, negative error number on failure.
481bee1138bSBartosz Golaszewski  */
482bee1138bSBartosz Golaszewski int nvmem_unregister_notifier(struct notifier_block *nb)
483bee1138bSBartosz Golaszewski {
484bee1138bSBartosz Golaszewski 	return blocking_notifier_chain_unregister(&nvmem_notifier, nb);
485bee1138bSBartosz Golaszewski }
486bee1138bSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_unregister_notifier);
487bee1138bSBartosz Golaszewski 
488b985f4cbSBartosz Golaszewski static int nvmem_add_cells_from_table(struct nvmem_device *nvmem)
489b985f4cbSBartosz Golaszewski {
490b985f4cbSBartosz Golaszewski 	const struct nvmem_cell_info *info;
491b985f4cbSBartosz Golaszewski 	struct nvmem_cell_table *table;
492b985f4cbSBartosz Golaszewski 	struct nvmem_cell *cell;
493b985f4cbSBartosz Golaszewski 	int rval = 0, i;
494b985f4cbSBartosz Golaszewski 
495b985f4cbSBartosz Golaszewski 	mutex_lock(&nvmem_cell_mutex);
496b985f4cbSBartosz Golaszewski 	list_for_each_entry(table, &nvmem_cell_tables, node) {
497b985f4cbSBartosz Golaszewski 		if (strcmp(nvmem_dev_name(nvmem), table->nvmem_name) == 0) {
498b985f4cbSBartosz Golaszewski 			for (i = 0; i < table->ncells; i++) {
499b985f4cbSBartosz Golaszewski 				info = &table->cells[i];
500b985f4cbSBartosz Golaszewski 
501b985f4cbSBartosz Golaszewski 				cell = kzalloc(sizeof(*cell), GFP_KERNEL);
502b985f4cbSBartosz Golaszewski 				if (!cell) {
503b985f4cbSBartosz Golaszewski 					rval = -ENOMEM;
504b985f4cbSBartosz Golaszewski 					goto out;
505b985f4cbSBartosz Golaszewski 				}
506b985f4cbSBartosz Golaszewski 
507b985f4cbSBartosz Golaszewski 				rval = nvmem_cell_info_to_nvmem_cell(nvmem,
508b985f4cbSBartosz Golaszewski 								     info,
509b985f4cbSBartosz Golaszewski 								     cell);
510b985f4cbSBartosz Golaszewski 				if (rval) {
511b985f4cbSBartosz Golaszewski 					kfree(cell);
512b985f4cbSBartosz Golaszewski 					goto out;
513b985f4cbSBartosz Golaszewski 				}
514b985f4cbSBartosz Golaszewski 
515b985f4cbSBartosz Golaszewski 				nvmem_cell_add(cell);
516b985f4cbSBartosz Golaszewski 			}
517b985f4cbSBartosz Golaszewski 		}
518b985f4cbSBartosz Golaszewski 	}
519b985f4cbSBartosz Golaszewski 
520b985f4cbSBartosz Golaszewski out:
521b985f4cbSBartosz Golaszewski 	mutex_unlock(&nvmem_cell_mutex);
522b985f4cbSBartosz Golaszewski 	return rval;
523b985f4cbSBartosz Golaszewski }
524b985f4cbSBartosz Golaszewski 
525e888d445SBartosz Golaszewski static struct nvmem_cell *
526506157beSBartosz Golaszewski nvmem_find_cell_by_name(struct nvmem_device *nvmem, const char *cell_id)
527506157beSBartosz Golaszewski {
528506157beSBartosz Golaszewski 	struct nvmem_cell *cell = NULL;
529506157beSBartosz Golaszewski 
530506157beSBartosz Golaszewski 	mutex_lock(&nvmem_mutex);
531506157beSBartosz Golaszewski 	list_for_each_entry(cell, &nvmem->cells, node) {
532506157beSBartosz Golaszewski 		if (strcmp(cell_id, cell->name) == 0)
533506157beSBartosz Golaszewski 			break;
534506157beSBartosz Golaszewski 	}
535506157beSBartosz Golaszewski 	mutex_unlock(&nvmem_mutex);
536506157beSBartosz Golaszewski 
537506157beSBartosz Golaszewski 	return cell;
538506157beSBartosz Golaszewski }
539506157beSBartosz Golaszewski 
540e888d445SBartosz Golaszewski static int nvmem_add_cells_from_of(struct nvmem_device *nvmem)
541e888d445SBartosz Golaszewski {
542e888d445SBartosz Golaszewski 	struct device_node *parent, *child;
543e888d445SBartosz Golaszewski 	struct device *dev = &nvmem->dev;
544e888d445SBartosz Golaszewski 	struct nvmem_cell *cell;
545e888d445SBartosz Golaszewski 	const __be32 *addr;
546e888d445SBartosz Golaszewski 	int len;
547e888d445SBartosz Golaszewski 
548e888d445SBartosz Golaszewski 	parent = dev->of_node;
549e888d445SBartosz Golaszewski 
550e888d445SBartosz Golaszewski 	for_each_child_of_node(parent, child) {
551e888d445SBartosz Golaszewski 		addr = of_get_property(child, "reg", &len);
552e888d445SBartosz Golaszewski 		if (!addr || (len < 2 * sizeof(u32))) {
553e888d445SBartosz Golaszewski 			dev_err(dev, "nvmem: invalid reg on %pOF\n", child);
554e888d445SBartosz Golaszewski 			return -EINVAL;
555e888d445SBartosz Golaszewski 		}
556e888d445SBartosz Golaszewski 
557e888d445SBartosz Golaszewski 		cell = kzalloc(sizeof(*cell), GFP_KERNEL);
558e888d445SBartosz Golaszewski 		if (!cell)
559e888d445SBartosz Golaszewski 			return -ENOMEM;
560e888d445SBartosz Golaszewski 
561e888d445SBartosz Golaszewski 		cell->nvmem = nvmem;
5620749aa25SSrinivas Kandagatla 		cell->np = of_node_get(child);
563e888d445SBartosz Golaszewski 		cell->offset = be32_to_cpup(addr++);
564e888d445SBartosz Golaszewski 		cell->bytes = be32_to_cpup(addr);
565badcdff1SRob Herring 		cell->name = kasprintf(GFP_KERNEL, "%pOFn", child);
566e888d445SBartosz Golaszewski 
567e888d445SBartosz Golaszewski 		addr = of_get_property(child, "bits", &len);
568e888d445SBartosz Golaszewski 		if (addr && len == (2 * sizeof(u32))) {
569e888d445SBartosz Golaszewski 			cell->bit_offset = be32_to_cpup(addr++);
570e888d445SBartosz Golaszewski 			cell->nbits = be32_to_cpup(addr);
571e888d445SBartosz Golaszewski 		}
572e888d445SBartosz Golaszewski 
573e888d445SBartosz Golaszewski 		if (cell->nbits)
574e888d445SBartosz Golaszewski 			cell->bytes = DIV_ROUND_UP(
575e888d445SBartosz Golaszewski 					cell->nbits + cell->bit_offset,
576e888d445SBartosz Golaszewski 					BITS_PER_BYTE);
577e888d445SBartosz Golaszewski 
578e888d445SBartosz Golaszewski 		if (!IS_ALIGNED(cell->offset, nvmem->stride)) {
579e888d445SBartosz Golaszewski 			dev_err(dev, "cell %s unaligned to nvmem stride %d\n",
580e888d445SBartosz Golaszewski 				cell->name, nvmem->stride);
581e888d445SBartosz Golaszewski 			/* Cells already added will be freed later. */
582badcdff1SRob Herring 			kfree(cell->name);
583e888d445SBartosz Golaszewski 			kfree(cell);
584e888d445SBartosz Golaszewski 			return -EINVAL;
585e888d445SBartosz Golaszewski 		}
586e888d445SBartosz Golaszewski 
587e888d445SBartosz Golaszewski 		nvmem_cell_add(cell);
588e888d445SBartosz Golaszewski 	}
589e888d445SBartosz Golaszewski 
590e888d445SBartosz Golaszewski 	return 0;
591e888d445SBartosz Golaszewski }
592e888d445SBartosz Golaszewski 
593eace75cfSSrinivas Kandagatla /**
594eace75cfSSrinivas Kandagatla  * nvmem_register() - Register a nvmem device for given nvmem_config.
595eace75cfSSrinivas Kandagatla  * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem
596eace75cfSSrinivas Kandagatla  *
597eace75cfSSrinivas Kandagatla  * @config: nvmem device configuration with which nvmem device is created.
598eace75cfSSrinivas Kandagatla  *
599eace75cfSSrinivas Kandagatla  * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device
600eace75cfSSrinivas Kandagatla  * on success.
601eace75cfSSrinivas Kandagatla  */
602eace75cfSSrinivas Kandagatla 
603eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem_register(const struct nvmem_config *config)
604eace75cfSSrinivas Kandagatla {
605eace75cfSSrinivas Kandagatla 	struct nvmem_device *nvmem;
606eace75cfSSrinivas Kandagatla 	int rval;
607eace75cfSSrinivas Kandagatla 
608eace75cfSSrinivas Kandagatla 	if (!config->dev)
609eace75cfSSrinivas Kandagatla 		return ERR_PTR(-EINVAL);
610eace75cfSSrinivas Kandagatla 
611eace75cfSSrinivas Kandagatla 	nvmem = kzalloc(sizeof(*nvmem), GFP_KERNEL);
612eace75cfSSrinivas Kandagatla 	if (!nvmem)
613eace75cfSSrinivas Kandagatla 		return ERR_PTR(-ENOMEM);
614eace75cfSSrinivas Kandagatla 
615eace75cfSSrinivas Kandagatla 	rval  = ida_simple_get(&nvmem_ida, 0, 0, GFP_KERNEL);
616eace75cfSSrinivas Kandagatla 	if (rval < 0) {
617eace75cfSSrinivas Kandagatla 		kfree(nvmem);
618eace75cfSSrinivas Kandagatla 		return ERR_PTR(rval);
619eace75cfSSrinivas Kandagatla 	}
620eace75cfSSrinivas Kandagatla 
621c1de7f43SBartosz Golaszewski 	kref_init(&nvmem->refcnt);
622c7235ee3SBartosz Golaszewski 	INIT_LIST_HEAD(&nvmem->cells);
623c1de7f43SBartosz Golaszewski 
624eace75cfSSrinivas Kandagatla 	nvmem->id = rval;
625eace75cfSSrinivas Kandagatla 	nvmem->owner = config->owner;
62617eb18d6SMasahiro Yamada 	if (!nvmem->owner && config->dev->driver)
62717eb18d6SMasahiro Yamada 		nvmem->owner = config->dev->driver->owner;
62899897efdSHeiner Kallweit 	nvmem->stride = config->stride ?: 1;
62999897efdSHeiner Kallweit 	nvmem->word_size = config->word_size ?: 1;
630795ddd18SSrinivas Kandagatla 	nvmem->size = config->size;
631eace75cfSSrinivas Kandagatla 	nvmem->dev.type = &nvmem_provider_type;
632eace75cfSSrinivas Kandagatla 	nvmem->dev.bus = &nvmem_bus_type;
633eace75cfSSrinivas Kandagatla 	nvmem->dev.parent = config->dev;
634795ddd18SSrinivas Kandagatla 	nvmem->priv = config->priv;
63516688453SAlexandre Belloni 	nvmem->type = config->type;
636795ddd18SSrinivas Kandagatla 	nvmem->reg_read = config->reg_read;
637795ddd18SSrinivas Kandagatla 	nvmem->reg_write = config->reg_write;
638fc2f9970SHeiner Kallweit 	nvmem->dev.of_node = config->dev->of_node;
639fd0f4906SAndrey Smirnov 
640fd0f4906SAndrey Smirnov 	if (config->id == -1 && config->name) {
641fd0f4906SAndrey Smirnov 		dev_set_name(&nvmem->dev, "%s", config->name);
642fd0f4906SAndrey Smirnov 	} else {
643eace75cfSSrinivas Kandagatla 		dev_set_name(&nvmem->dev, "%s%d",
6445253193dSAban Bedel 			     config->name ? : "nvmem",
6455253193dSAban Bedel 			     config->name ? config->id : nvmem->id);
646fd0f4906SAndrey Smirnov 	}
647eace75cfSSrinivas Kandagatla 
648fc2f9970SHeiner Kallweit 	nvmem->read_only = device_property_present(config->dev, "read-only") |
649eace75cfSSrinivas Kandagatla 			   config->read_only;
650eace75cfSSrinivas Kandagatla 
651811b0d65SAndrew Lunn 	if (config->root_only)
652811b0d65SAndrew Lunn 		nvmem->dev.groups = nvmem->read_only ?
653811b0d65SAndrew Lunn 			nvmem_ro_root_dev_groups :
654811b0d65SAndrew Lunn 			nvmem_rw_root_dev_groups;
655811b0d65SAndrew Lunn 	else
656811b0d65SAndrew Lunn 		nvmem->dev.groups = nvmem->read_only ?
657811b0d65SAndrew Lunn 			nvmem_ro_dev_groups :
658eace75cfSSrinivas Kandagatla 			nvmem_rw_dev_groups;
659eace75cfSSrinivas Kandagatla 
660eace75cfSSrinivas Kandagatla 	device_initialize(&nvmem->dev);
661eace75cfSSrinivas Kandagatla 
662eace75cfSSrinivas Kandagatla 	dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name);
663eace75cfSSrinivas Kandagatla 
664eace75cfSSrinivas Kandagatla 	rval = device_add(&nvmem->dev);
665b6c217abSAndrew Lunn 	if (rval)
6663360acdfSJohan Hovold 		goto err_put_device;
667b6c217abSAndrew Lunn 
668b6c217abSAndrew Lunn 	if (config->compat) {
669b6c217abSAndrew Lunn 		rval = nvmem_setup_compat(nvmem, config);
670b6c217abSAndrew Lunn 		if (rval)
6713360acdfSJohan Hovold 			goto err_device_del;
672eace75cfSSrinivas Kandagatla 	}
673eace75cfSSrinivas Kandagatla 
674fa72d847SBartosz Golaszewski 	if (config->cells) {
675fa72d847SBartosz Golaszewski 		rval = nvmem_add_cells(nvmem, config->cells, config->ncells);
676fa72d847SBartosz Golaszewski 		if (rval)
677fa72d847SBartosz Golaszewski 			goto err_teardown_compat;
678fa72d847SBartosz Golaszewski 	}
679eace75cfSSrinivas Kandagatla 
680b985f4cbSBartosz Golaszewski 	rval = nvmem_add_cells_from_table(nvmem);
681b985f4cbSBartosz Golaszewski 	if (rval)
682b985f4cbSBartosz Golaszewski 		goto err_remove_cells;
683b985f4cbSBartosz Golaszewski 
684e888d445SBartosz Golaszewski 	rval = nvmem_add_cells_from_of(nvmem);
685e888d445SBartosz Golaszewski 	if (rval)
686e888d445SBartosz Golaszewski 		goto err_remove_cells;
687e888d445SBartosz Golaszewski 
688bee1138bSBartosz Golaszewski 	rval = blocking_notifier_call_chain(&nvmem_notifier, NVMEM_ADD, nvmem);
689bee1138bSBartosz Golaszewski 	if (rval)
690bee1138bSBartosz Golaszewski 		goto err_remove_cells;
691bee1138bSBartosz Golaszewski 
692eace75cfSSrinivas Kandagatla 	return nvmem;
6933360acdfSJohan Hovold 
694b985f4cbSBartosz Golaszewski err_remove_cells:
695b985f4cbSBartosz Golaszewski 	nvmem_device_remove_all_cells(nvmem);
696fa72d847SBartosz Golaszewski err_teardown_compat:
697fa72d847SBartosz Golaszewski 	if (config->compat)
698fa72d847SBartosz Golaszewski 		device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom);
6993360acdfSJohan Hovold err_device_del:
7003360acdfSJohan Hovold 	device_del(&nvmem->dev);
7013360acdfSJohan Hovold err_put_device:
7023360acdfSJohan Hovold 	put_device(&nvmem->dev);
7033360acdfSJohan Hovold 
704b6c217abSAndrew Lunn 	return ERR_PTR(rval);
705eace75cfSSrinivas Kandagatla }
706eace75cfSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_register);
707eace75cfSSrinivas Kandagatla 
708c1de7f43SBartosz Golaszewski static void nvmem_device_release(struct kref *kref)
709c1de7f43SBartosz Golaszewski {
710c1de7f43SBartosz Golaszewski 	struct nvmem_device *nvmem;
711c1de7f43SBartosz Golaszewski 
712c1de7f43SBartosz Golaszewski 	nvmem = container_of(kref, struct nvmem_device, refcnt);
713c1de7f43SBartosz Golaszewski 
714bee1138bSBartosz Golaszewski 	blocking_notifier_call_chain(&nvmem_notifier, NVMEM_REMOVE, nvmem);
715bee1138bSBartosz Golaszewski 
716c1de7f43SBartosz Golaszewski 	if (nvmem->flags & FLAG_COMPAT)
717c1de7f43SBartosz Golaszewski 		device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom);
718c1de7f43SBartosz Golaszewski 
719c1de7f43SBartosz Golaszewski 	nvmem_device_remove_all_cells(nvmem);
720c1de7f43SBartosz Golaszewski 	device_del(&nvmem->dev);
721c1de7f43SBartosz Golaszewski 	put_device(&nvmem->dev);
722c1de7f43SBartosz Golaszewski }
723c1de7f43SBartosz Golaszewski 
724eace75cfSSrinivas Kandagatla /**
725eace75cfSSrinivas Kandagatla  * nvmem_unregister() - Unregister previously registered nvmem device
726eace75cfSSrinivas Kandagatla  *
727eace75cfSSrinivas Kandagatla  * @nvmem: Pointer to previously registered nvmem device.
728eace75cfSSrinivas Kandagatla  */
729bf58e882SBartosz Golaszewski void nvmem_unregister(struct nvmem_device *nvmem)
730eace75cfSSrinivas Kandagatla {
731c1de7f43SBartosz Golaszewski 	kref_put(&nvmem->refcnt, nvmem_device_release);
732eace75cfSSrinivas Kandagatla }
733eace75cfSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_unregister);
734eace75cfSSrinivas Kandagatla 
735f1f50ecaSAndrey Smirnov static void devm_nvmem_release(struct device *dev, void *res)
736f1f50ecaSAndrey Smirnov {
737bf58e882SBartosz Golaszewski 	nvmem_unregister(*(struct nvmem_device **)res);
738f1f50ecaSAndrey Smirnov }
739f1f50ecaSAndrey Smirnov 
740f1f50ecaSAndrey Smirnov /**
741f1f50ecaSAndrey Smirnov  * devm_nvmem_register() - Register a managed nvmem device for given
742f1f50ecaSAndrey Smirnov  * nvmem_config.
743f1f50ecaSAndrey Smirnov  * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem
744f1f50ecaSAndrey Smirnov  *
745b378c779SSrinivas Kandagatla  * @dev: Device that uses the nvmem device.
746f1f50ecaSAndrey Smirnov  * @config: nvmem device configuration with which nvmem device is created.
747f1f50ecaSAndrey Smirnov  *
748f1f50ecaSAndrey Smirnov  * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device
749f1f50ecaSAndrey Smirnov  * on success.
750f1f50ecaSAndrey Smirnov  */
751f1f50ecaSAndrey Smirnov struct nvmem_device *devm_nvmem_register(struct device *dev,
752f1f50ecaSAndrey Smirnov 					 const struct nvmem_config *config)
753f1f50ecaSAndrey Smirnov {
754f1f50ecaSAndrey Smirnov 	struct nvmem_device **ptr, *nvmem;
755f1f50ecaSAndrey Smirnov 
756f1f50ecaSAndrey Smirnov 	ptr = devres_alloc(devm_nvmem_release, sizeof(*ptr), GFP_KERNEL);
757f1f50ecaSAndrey Smirnov 	if (!ptr)
758f1f50ecaSAndrey Smirnov 		return ERR_PTR(-ENOMEM);
759f1f50ecaSAndrey Smirnov 
760f1f50ecaSAndrey Smirnov 	nvmem = nvmem_register(config);
761f1f50ecaSAndrey Smirnov 
762f1f50ecaSAndrey Smirnov 	if (!IS_ERR(nvmem)) {
763f1f50ecaSAndrey Smirnov 		*ptr = nvmem;
764f1f50ecaSAndrey Smirnov 		devres_add(dev, ptr);
765f1f50ecaSAndrey Smirnov 	} else {
766f1f50ecaSAndrey Smirnov 		devres_free(ptr);
767f1f50ecaSAndrey Smirnov 	}
768f1f50ecaSAndrey Smirnov 
769f1f50ecaSAndrey Smirnov 	return nvmem;
770f1f50ecaSAndrey Smirnov }
771f1f50ecaSAndrey Smirnov EXPORT_SYMBOL_GPL(devm_nvmem_register);
772f1f50ecaSAndrey Smirnov 
773f1f50ecaSAndrey Smirnov static int devm_nvmem_match(struct device *dev, void *res, void *data)
774f1f50ecaSAndrey Smirnov {
775f1f50ecaSAndrey Smirnov 	struct nvmem_device **r = res;
776f1f50ecaSAndrey Smirnov 
777f1f50ecaSAndrey Smirnov 	return *r == data;
778f1f50ecaSAndrey Smirnov }
779f1f50ecaSAndrey Smirnov 
780f1f50ecaSAndrey Smirnov /**
781f1f50ecaSAndrey Smirnov  * devm_nvmem_unregister() - Unregister previously registered managed nvmem
782f1f50ecaSAndrey Smirnov  * device.
783f1f50ecaSAndrey Smirnov  *
784b378c779SSrinivas Kandagatla  * @dev: Device that uses the nvmem device.
785f1f50ecaSAndrey Smirnov  * @nvmem: Pointer to previously registered nvmem device.
786f1f50ecaSAndrey Smirnov  *
787f1f50ecaSAndrey Smirnov  * Return: Will be an negative on error or a zero on success.
788f1f50ecaSAndrey Smirnov  */
789f1f50ecaSAndrey Smirnov int devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem)
790f1f50ecaSAndrey Smirnov {
791f1f50ecaSAndrey Smirnov 	return devres_release(dev, devm_nvmem_release, devm_nvmem_match, nvmem);
792f1f50ecaSAndrey Smirnov }
793f1f50ecaSAndrey Smirnov EXPORT_SYMBOL(devm_nvmem_unregister);
794f1f50ecaSAndrey Smirnov 
79569aba794SSrinivas Kandagatla static struct nvmem_device *__nvmem_device_get(struct device_node *np,
796506157beSBartosz Golaszewski 					       const char *nvmem_name)
79769aba794SSrinivas Kandagatla {
79869aba794SSrinivas Kandagatla 	struct nvmem_device *nvmem = NULL;
79969aba794SSrinivas Kandagatla 
800c7235ee3SBartosz Golaszewski 	mutex_lock(&nvmem_mutex);
801506157beSBartosz Golaszewski 	nvmem = np ? of_nvmem_find(np) : nvmem_find(nvmem_name);
80269aba794SSrinivas Kandagatla 	mutex_unlock(&nvmem_mutex);
803c7235ee3SBartosz Golaszewski 	if (!nvmem)
804c7235ee3SBartosz Golaszewski 		return ERR_PTR(-EPROBE_DEFER);
80569aba794SSrinivas Kandagatla 
80669aba794SSrinivas Kandagatla 	if (!try_module_get(nvmem->owner)) {
80769aba794SSrinivas Kandagatla 		dev_err(&nvmem->dev,
80869aba794SSrinivas Kandagatla 			"could not increase module refcount for cell %s\n",
8095db652c9SBartosz Golaszewski 			nvmem_dev_name(nvmem));
81069aba794SSrinivas Kandagatla 
81169aba794SSrinivas Kandagatla 		return ERR_PTR(-EINVAL);
81269aba794SSrinivas Kandagatla 	}
81369aba794SSrinivas Kandagatla 
814c1de7f43SBartosz Golaszewski 	kref_get(&nvmem->refcnt);
815c1de7f43SBartosz Golaszewski 
81669aba794SSrinivas Kandagatla 	return nvmem;
81769aba794SSrinivas Kandagatla }
81869aba794SSrinivas Kandagatla 
81969aba794SSrinivas Kandagatla static void __nvmem_device_put(struct nvmem_device *nvmem)
82069aba794SSrinivas Kandagatla {
82169aba794SSrinivas Kandagatla 	module_put(nvmem->owner);
822c1de7f43SBartosz Golaszewski 	kref_put(&nvmem->refcnt, nvmem_device_release);
82369aba794SSrinivas Kandagatla }
82469aba794SSrinivas Kandagatla 
825e701c67cSMasahiro Yamada #if IS_ENABLED(CONFIG_OF)
826e2a5402eSSrinivas Kandagatla /**
827e2a5402eSSrinivas Kandagatla  * of_nvmem_device_get() - Get nvmem device from a given id
828e2a5402eSSrinivas Kandagatla  *
82929143268SVivek Gautam  * @np: Device tree node that uses the nvmem device.
830e2a5402eSSrinivas Kandagatla  * @id: nvmem name from nvmem-names property.
831e2a5402eSSrinivas Kandagatla  *
832e2a5402eSSrinivas Kandagatla  * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device
833e2a5402eSSrinivas Kandagatla  * on success.
834e2a5402eSSrinivas Kandagatla  */
835e2a5402eSSrinivas Kandagatla struct nvmem_device *of_nvmem_device_get(struct device_node *np, const char *id)
836e2a5402eSSrinivas Kandagatla {
837e2a5402eSSrinivas Kandagatla 
838e2a5402eSSrinivas Kandagatla 	struct device_node *nvmem_np;
839e2a5402eSSrinivas Kandagatla 	int index;
840e2a5402eSSrinivas Kandagatla 
841e2a5402eSSrinivas Kandagatla 	index = of_property_match_string(np, "nvmem-names", id);
842e2a5402eSSrinivas Kandagatla 
843e2a5402eSSrinivas Kandagatla 	nvmem_np = of_parse_phandle(np, "nvmem", index);
844e2a5402eSSrinivas Kandagatla 	if (!nvmem_np)
845e2a5402eSSrinivas Kandagatla 		return ERR_PTR(-EINVAL);
846e2a5402eSSrinivas Kandagatla 
847506157beSBartosz Golaszewski 	return __nvmem_device_get(nvmem_np, NULL);
848e2a5402eSSrinivas Kandagatla }
849e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_nvmem_device_get);
850e2a5402eSSrinivas Kandagatla #endif
851e2a5402eSSrinivas Kandagatla 
852e2a5402eSSrinivas Kandagatla /**
853e2a5402eSSrinivas Kandagatla  * nvmem_device_get() - Get nvmem device from a given id
854e2a5402eSSrinivas Kandagatla  *
85529143268SVivek Gautam  * @dev: Device that uses the nvmem device.
85629143268SVivek Gautam  * @dev_name: name of the requested nvmem device.
857e2a5402eSSrinivas Kandagatla  *
858e2a5402eSSrinivas Kandagatla  * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device
859e2a5402eSSrinivas Kandagatla  * on success.
860e2a5402eSSrinivas Kandagatla  */
861e2a5402eSSrinivas Kandagatla struct nvmem_device *nvmem_device_get(struct device *dev, const char *dev_name)
862e2a5402eSSrinivas Kandagatla {
863e2a5402eSSrinivas Kandagatla 	if (dev->of_node) { /* try dt first */
864e2a5402eSSrinivas Kandagatla 		struct nvmem_device *nvmem;
865e2a5402eSSrinivas Kandagatla 
866e2a5402eSSrinivas Kandagatla 		nvmem = of_nvmem_device_get(dev->of_node, dev_name);
867e2a5402eSSrinivas Kandagatla 
868e2a5402eSSrinivas Kandagatla 		if (!IS_ERR(nvmem) || PTR_ERR(nvmem) == -EPROBE_DEFER)
869e2a5402eSSrinivas Kandagatla 			return nvmem;
870e2a5402eSSrinivas Kandagatla 
871e2a5402eSSrinivas Kandagatla 	}
872e2a5402eSSrinivas Kandagatla 
873e2a5402eSSrinivas Kandagatla 	return nvmem_find(dev_name);
874e2a5402eSSrinivas Kandagatla }
875e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_get);
876e2a5402eSSrinivas Kandagatla 
877e2a5402eSSrinivas Kandagatla static int devm_nvmem_device_match(struct device *dev, void *res, void *data)
878e2a5402eSSrinivas Kandagatla {
879e2a5402eSSrinivas Kandagatla 	struct nvmem_device **nvmem = res;
880e2a5402eSSrinivas Kandagatla 
881e2a5402eSSrinivas Kandagatla 	if (WARN_ON(!nvmem || !*nvmem))
882e2a5402eSSrinivas Kandagatla 		return 0;
883e2a5402eSSrinivas Kandagatla 
884e2a5402eSSrinivas Kandagatla 	return *nvmem == data;
885e2a5402eSSrinivas Kandagatla }
886e2a5402eSSrinivas Kandagatla 
887e2a5402eSSrinivas Kandagatla static void devm_nvmem_device_release(struct device *dev, void *res)
888e2a5402eSSrinivas Kandagatla {
889e2a5402eSSrinivas Kandagatla 	nvmem_device_put(*(struct nvmem_device **)res);
890e2a5402eSSrinivas Kandagatla }
891e2a5402eSSrinivas Kandagatla 
892e2a5402eSSrinivas Kandagatla /**
893e2a5402eSSrinivas Kandagatla  * devm_nvmem_device_put() - put alredy got nvmem device
894e2a5402eSSrinivas Kandagatla  *
89529143268SVivek Gautam  * @dev: Device that uses the nvmem device.
896e2a5402eSSrinivas Kandagatla  * @nvmem: pointer to nvmem device allocated by devm_nvmem_cell_get(),
897e2a5402eSSrinivas Kandagatla  * that needs to be released.
898e2a5402eSSrinivas Kandagatla  */
899e2a5402eSSrinivas Kandagatla void devm_nvmem_device_put(struct device *dev, struct nvmem_device *nvmem)
900e2a5402eSSrinivas Kandagatla {
901e2a5402eSSrinivas Kandagatla 	int ret;
902e2a5402eSSrinivas Kandagatla 
903e2a5402eSSrinivas Kandagatla 	ret = devres_release(dev, devm_nvmem_device_release,
904e2a5402eSSrinivas Kandagatla 			     devm_nvmem_device_match, nvmem);
905e2a5402eSSrinivas Kandagatla 
906e2a5402eSSrinivas Kandagatla 	WARN_ON(ret);
907e2a5402eSSrinivas Kandagatla }
908e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_device_put);
909e2a5402eSSrinivas Kandagatla 
910e2a5402eSSrinivas Kandagatla /**
911e2a5402eSSrinivas Kandagatla  * nvmem_device_put() - put alredy got nvmem device
912e2a5402eSSrinivas Kandagatla  *
913e2a5402eSSrinivas Kandagatla  * @nvmem: pointer to nvmem device that needs to be released.
914e2a5402eSSrinivas Kandagatla  */
915e2a5402eSSrinivas Kandagatla void nvmem_device_put(struct nvmem_device *nvmem)
916e2a5402eSSrinivas Kandagatla {
917e2a5402eSSrinivas Kandagatla 	__nvmem_device_put(nvmem);
918e2a5402eSSrinivas Kandagatla }
919e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_put);
920e2a5402eSSrinivas Kandagatla 
921e2a5402eSSrinivas Kandagatla /**
922e2a5402eSSrinivas Kandagatla  * devm_nvmem_device_get() - Get nvmem cell of device form a given id
923e2a5402eSSrinivas Kandagatla  *
92429143268SVivek Gautam  * @dev: Device that requests the nvmem device.
92529143268SVivek Gautam  * @id: name id for the requested nvmem device.
926e2a5402eSSrinivas Kandagatla  *
927e2a5402eSSrinivas Kandagatla  * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_cell
928e2a5402eSSrinivas Kandagatla  * on success.  The nvmem_cell will be freed by the automatically once the
929e2a5402eSSrinivas Kandagatla  * device is freed.
930e2a5402eSSrinivas Kandagatla  */
931e2a5402eSSrinivas Kandagatla struct nvmem_device *devm_nvmem_device_get(struct device *dev, const char *id)
932e2a5402eSSrinivas Kandagatla {
933e2a5402eSSrinivas Kandagatla 	struct nvmem_device **ptr, *nvmem;
934e2a5402eSSrinivas Kandagatla 
935e2a5402eSSrinivas Kandagatla 	ptr = devres_alloc(devm_nvmem_device_release, sizeof(*ptr), GFP_KERNEL);
936e2a5402eSSrinivas Kandagatla 	if (!ptr)
937e2a5402eSSrinivas Kandagatla 		return ERR_PTR(-ENOMEM);
938e2a5402eSSrinivas Kandagatla 
939e2a5402eSSrinivas Kandagatla 	nvmem = nvmem_device_get(dev, id);
940e2a5402eSSrinivas Kandagatla 	if (!IS_ERR(nvmem)) {
941e2a5402eSSrinivas Kandagatla 		*ptr = nvmem;
942e2a5402eSSrinivas Kandagatla 		devres_add(dev, ptr);
943e2a5402eSSrinivas Kandagatla 	} else {
944e2a5402eSSrinivas Kandagatla 		devres_free(ptr);
945e2a5402eSSrinivas Kandagatla 	}
946e2a5402eSSrinivas Kandagatla 
947e2a5402eSSrinivas Kandagatla 	return nvmem;
948e2a5402eSSrinivas Kandagatla }
949e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_device_get);
950e2a5402eSSrinivas Kandagatla 
951506157beSBartosz Golaszewski static struct nvmem_cell *
952506157beSBartosz Golaszewski nvmem_cell_get_from_lookup(struct device *dev, const char *con_id)
95369aba794SSrinivas Kandagatla {
954506157beSBartosz Golaszewski 	struct nvmem_cell *cell = ERR_PTR(-ENOENT);
955506157beSBartosz Golaszewski 	struct nvmem_cell_lookup *lookup;
95669aba794SSrinivas Kandagatla 	struct nvmem_device *nvmem;
957506157beSBartosz Golaszewski 	const char *dev_id;
95869aba794SSrinivas Kandagatla 
959506157beSBartosz Golaszewski 	if (!dev)
960506157beSBartosz Golaszewski 		return ERR_PTR(-EINVAL);
96169aba794SSrinivas Kandagatla 
962506157beSBartosz Golaszewski 	dev_id = dev_name(dev);
963506157beSBartosz Golaszewski 
964506157beSBartosz Golaszewski 	mutex_lock(&nvmem_lookup_mutex);
965506157beSBartosz Golaszewski 
966506157beSBartosz Golaszewski 	list_for_each_entry(lookup, &nvmem_lookup_list, node) {
967506157beSBartosz Golaszewski 		if ((strcmp(lookup->dev_id, dev_id) == 0) &&
968506157beSBartosz Golaszewski 		    (strcmp(lookup->con_id, con_id) == 0)) {
969506157beSBartosz Golaszewski 			/* This is the right entry. */
970506157beSBartosz Golaszewski 			nvmem = __nvmem_device_get(NULL, lookup->nvmem_name);
971cccb3b19SBartosz Golaszewski 			if (IS_ERR(nvmem)) {
972506157beSBartosz Golaszewski 				/* Provider may not be registered yet. */
973cccb3b19SBartosz Golaszewski 				cell = ERR_CAST(nvmem);
974506157beSBartosz Golaszewski 				goto out;
975506157beSBartosz Golaszewski 			}
976506157beSBartosz Golaszewski 
977506157beSBartosz Golaszewski 			cell = nvmem_find_cell_by_name(nvmem,
978506157beSBartosz Golaszewski 						       lookup->cell_name);
979506157beSBartosz Golaszewski 			if (!cell) {
980506157beSBartosz Golaszewski 				__nvmem_device_put(nvmem);
981cccb3b19SBartosz Golaszewski 				cell = ERR_PTR(-ENOENT);
982506157beSBartosz Golaszewski 				goto out;
983506157beSBartosz Golaszewski 			}
984506157beSBartosz Golaszewski 		}
985506157beSBartosz Golaszewski 	}
986506157beSBartosz Golaszewski 
987506157beSBartosz Golaszewski out:
988506157beSBartosz Golaszewski 	mutex_unlock(&nvmem_lookup_mutex);
98969aba794SSrinivas Kandagatla 	return cell;
99069aba794SSrinivas Kandagatla }
99169aba794SSrinivas Kandagatla 
992e701c67cSMasahiro Yamada #if IS_ENABLED(CONFIG_OF)
9933c53e235SArnd Bergmann static struct nvmem_cell *
9940749aa25SSrinivas Kandagatla nvmem_find_cell_by_node(struct nvmem_device *nvmem, struct device_node *np)
9953c53e235SArnd Bergmann {
9963c53e235SArnd Bergmann 	struct nvmem_cell *cell = NULL;
9973c53e235SArnd Bergmann 
9983c53e235SArnd Bergmann 	mutex_lock(&nvmem_mutex);
9993c53e235SArnd Bergmann 	list_for_each_entry(cell, &nvmem->cells, node) {
10000749aa25SSrinivas Kandagatla 		if (np == cell->np)
10013c53e235SArnd Bergmann 			break;
10023c53e235SArnd Bergmann 	}
10033c53e235SArnd Bergmann 	mutex_unlock(&nvmem_mutex);
10043c53e235SArnd Bergmann 
10053c53e235SArnd Bergmann 	return cell;
10063c53e235SArnd Bergmann }
10073c53e235SArnd Bergmann 
100869aba794SSrinivas Kandagatla /**
100969aba794SSrinivas Kandagatla  * of_nvmem_cell_get() - Get a nvmem cell from given device node and cell id
101069aba794SSrinivas Kandagatla  *
101129143268SVivek Gautam  * @np: Device tree node that uses the nvmem cell.
1012165589f0SBartosz Golaszewski  * @id: nvmem cell name from nvmem-cell-names property, or NULL
1013fd0c478cSVivek Gautam  *      for the cell at index 0 (the lone cell with no accompanying
1014fd0c478cSVivek Gautam  *      nvmem-cell-names property).
101569aba794SSrinivas Kandagatla  *
101669aba794SSrinivas Kandagatla  * Return: Will be an ERR_PTR() on error or a valid pointer
101769aba794SSrinivas Kandagatla  * to a struct nvmem_cell.  The nvmem_cell will be freed by the
101869aba794SSrinivas Kandagatla  * nvmem_cell_put().
101969aba794SSrinivas Kandagatla  */
1020165589f0SBartosz Golaszewski struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *id)
102169aba794SSrinivas Kandagatla {
102269aba794SSrinivas Kandagatla 	struct device_node *cell_np, *nvmem_np;
102369aba794SSrinivas Kandagatla 	struct nvmem_device *nvmem;
1024e888d445SBartosz Golaszewski 	struct nvmem_cell *cell;
1025fd0c478cSVivek Gautam 	int index = 0;
102669aba794SSrinivas Kandagatla 
1027fd0c478cSVivek Gautam 	/* if cell name exists, find index to the name */
1028165589f0SBartosz Golaszewski 	if (id)
1029165589f0SBartosz Golaszewski 		index = of_property_match_string(np, "nvmem-cell-names", id);
103069aba794SSrinivas Kandagatla 
103169aba794SSrinivas Kandagatla 	cell_np = of_parse_phandle(np, "nvmem-cells", index);
103269aba794SSrinivas Kandagatla 	if (!cell_np)
103369aba794SSrinivas Kandagatla 		return ERR_PTR(-EINVAL);
103469aba794SSrinivas Kandagatla 
103569aba794SSrinivas Kandagatla 	nvmem_np = of_get_next_parent(cell_np);
103669aba794SSrinivas Kandagatla 	if (!nvmem_np)
103769aba794SSrinivas Kandagatla 		return ERR_PTR(-EINVAL);
103869aba794SSrinivas Kandagatla 
1039506157beSBartosz Golaszewski 	nvmem = __nvmem_device_get(nvmem_np, NULL);
1040aad8d097SMasahiro Yamada 	of_node_put(nvmem_np);
104169aba794SSrinivas Kandagatla 	if (IS_ERR(nvmem))
104269aba794SSrinivas Kandagatla 		return ERR_CAST(nvmem);
104369aba794SSrinivas Kandagatla 
10440749aa25SSrinivas Kandagatla 	cell = nvmem_find_cell_by_node(nvmem, cell_np);
104569aba794SSrinivas Kandagatla 	if (!cell) {
1046e888d445SBartosz Golaszewski 		__nvmem_device_put(nvmem);
1047e888d445SBartosz Golaszewski 		return ERR_PTR(-ENOENT);
104869aba794SSrinivas Kandagatla 	}
104969aba794SSrinivas Kandagatla 
105069aba794SSrinivas Kandagatla 	return cell;
105169aba794SSrinivas Kandagatla }
105269aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_nvmem_cell_get);
105369aba794SSrinivas Kandagatla #endif
105469aba794SSrinivas Kandagatla 
105569aba794SSrinivas Kandagatla /**
105669aba794SSrinivas Kandagatla  * nvmem_cell_get() - Get nvmem cell of device form a given cell name
105769aba794SSrinivas Kandagatla  *
105829143268SVivek Gautam  * @dev: Device that requests the nvmem cell.
1059165589f0SBartosz Golaszewski  * @id: nvmem cell name to get (this corresponds with the name from the
1060165589f0SBartosz Golaszewski  *      nvmem-cell-names property for DT systems and with the con_id from
1061165589f0SBartosz Golaszewski  *      the lookup entry for non-DT systems).
106269aba794SSrinivas Kandagatla  *
106369aba794SSrinivas Kandagatla  * Return: Will be an ERR_PTR() on error or a valid pointer
106469aba794SSrinivas Kandagatla  * to a struct nvmem_cell.  The nvmem_cell will be freed by the
106569aba794SSrinivas Kandagatla  * nvmem_cell_put().
106669aba794SSrinivas Kandagatla  */
1067165589f0SBartosz Golaszewski struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *id)
106869aba794SSrinivas Kandagatla {
106969aba794SSrinivas Kandagatla 	struct nvmem_cell *cell;
107069aba794SSrinivas Kandagatla 
107169aba794SSrinivas Kandagatla 	if (dev->of_node) { /* try dt first */
1072165589f0SBartosz Golaszewski 		cell = of_nvmem_cell_get(dev->of_node, id);
107369aba794SSrinivas Kandagatla 		if (!IS_ERR(cell) || PTR_ERR(cell) == -EPROBE_DEFER)
107469aba794SSrinivas Kandagatla 			return cell;
107569aba794SSrinivas Kandagatla 	}
107669aba794SSrinivas Kandagatla 
1077165589f0SBartosz Golaszewski 	/* NULL cell id only allowed for device tree; invalid otherwise */
1078165589f0SBartosz Golaszewski 	if (!id)
107987ed1405SDouglas Anderson 		return ERR_PTR(-EINVAL);
108087ed1405SDouglas Anderson 
1081165589f0SBartosz Golaszewski 	return nvmem_cell_get_from_lookup(dev, id);
108269aba794SSrinivas Kandagatla }
108369aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_get);
108469aba794SSrinivas Kandagatla 
108569aba794SSrinivas Kandagatla static void devm_nvmem_cell_release(struct device *dev, void *res)
108669aba794SSrinivas Kandagatla {
108769aba794SSrinivas Kandagatla 	nvmem_cell_put(*(struct nvmem_cell **)res);
108869aba794SSrinivas Kandagatla }
108969aba794SSrinivas Kandagatla 
109069aba794SSrinivas Kandagatla /**
109169aba794SSrinivas Kandagatla  * devm_nvmem_cell_get() - Get nvmem cell of device form a given id
109269aba794SSrinivas Kandagatla  *
109329143268SVivek Gautam  * @dev: Device that requests the nvmem cell.
109429143268SVivek Gautam  * @id: nvmem cell name id to get.
109569aba794SSrinivas Kandagatla  *
109669aba794SSrinivas Kandagatla  * Return: Will be an ERR_PTR() on error or a valid pointer
109769aba794SSrinivas Kandagatla  * to a struct nvmem_cell.  The nvmem_cell will be freed by the
109869aba794SSrinivas Kandagatla  * automatically once the device is freed.
109969aba794SSrinivas Kandagatla  */
110069aba794SSrinivas Kandagatla struct nvmem_cell *devm_nvmem_cell_get(struct device *dev, const char *id)
110169aba794SSrinivas Kandagatla {
110269aba794SSrinivas Kandagatla 	struct nvmem_cell **ptr, *cell;
110369aba794SSrinivas Kandagatla 
110469aba794SSrinivas Kandagatla 	ptr = devres_alloc(devm_nvmem_cell_release, sizeof(*ptr), GFP_KERNEL);
110569aba794SSrinivas Kandagatla 	if (!ptr)
110669aba794SSrinivas Kandagatla 		return ERR_PTR(-ENOMEM);
110769aba794SSrinivas Kandagatla 
110869aba794SSrinivas Kandagatla 	cell = nvmem_cell_get(dev, id);
110969aba794SSrinivas Kandagatla 	if (!IS_ERR(cell)) {
111069aba794SSrinivas Kandagatla 		*ptr = cell;
111169aba794SSrinivas Kandagatla 		devres_add(dev, ptr);
111269aba794SSrinivas Kandagatla 	} else {
111369aba794SSrinivas Kandagatla 		devres_free(ptr);
111469aba794SSrinivas Kandagatla 	}
111569aba794SSrinivas Kandagatla 
111669aba794SSrinivas Kandagatla 	return cell;
111769aba794SSrinivas Kandagatla }
111869aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_cell_get);
111969aba794SSrinivas Kandagatla 
112069aba794SSrinivas Kandagatla static int devm_nvmem_cell_match(struct device *dev, void *res, void *data)
112169aba794SSrinivas Kandagatla {
112269aba794SSrinivas Kandagatla 	struct nvmem_cell **c = res;
112369aba794SSrinivas Kandagatla 
112469aba794SSrinivas Kandagatla 	if (WARN_ON(!c || !*c))
112569aba794SSrinivas Kandagatla 		return 0;
112669aba794SSrinivas Kandagatla 
112769aba794SSrinivas Kandagatla 	return *c == data;
112869aba794SSrinivas Kandagatla }
112969aba794SSrinivas Kandagatla 
113069aba794SSrinivas Kandagatla /**
113169aba794SSrinivas Kandagatla  * devm_nvmem_cell_put() - Release previously allocated nvmem cell
113269aba794SSrinivas Kandagatla  * from devm_nvmem_cell_get.
113369aba794SSrinivas Kandagatla  *
113429143268SVivek Gautam  * @dev: Device that requests the nvmem cell.
113529143268SVivek Gautam  * @cell: Previously allocated nvmem cell by devm_nvmem_cell_get().
113669aba794SSrinivas Kandagatla  */
113769aba794SSrinivas Kandagatla void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell)
113869aba794SSrinivas Kandagatla {
113969aba794SSrinivas Kandagatla 	int ret;
114069aba794SSrinivas Kandagatla 
114169aba794SSrinivas Kandagatla 	ret = devres_release(dev, devm_nvmem_cell_release,
114269aba794SSrinivas Kandagatla 				devm_nvmem_cell_match, cell);
114369aba794SSrinivas Kandagatla 
114469aba794SSrinivas Kandagatla 	WARN_ON(ret);
114569aba794SSrinivas Kandagatla }
114669aba794SSrinivas Kandagatla EXPORT_SYMBOL(devm_nvmem_cell_put);
114769aba794SSrinivas Kandagatla 
114869aba794SSrinivas Kandagatla /**
114969aba794SSrinivas Kandagatla  * nvmem_cell_put() - Release previously allocated nvmem cell.
115069aba794SSrinivas Kandagatla  *
115129143268SVivek Gautam  * @cell: Previously allocated nvmem cell by nvmem_cell_get().
115269aba794SSrinivas Kandagatla  */
115369aba794SSrinivas Kandagatla void nvmem_cell_put(struct nvmem_cell *cell)
115469aba794SSrinivas Kandagatla {
115569aba794SSrinivas Kandagatla 	struct nvmem_device *nvmem = cell->nvmem;
115669aba794SSrinivas Kandagatla 
115769aba794SSrinivas Kandagatla 	__nvmem_device_put(nvmem);
115869aba794SSrinivas Kandagatla }
115969aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_put);
116069aba794SSrinivas Kandagatla 
1161f7c04f16SMasahiro Yamada static void nvmem_shift_read_buffer_in_place(struct nvmem_cell *cell, void *buf)
116269aba794SSrinivas Kandagatla {
116369aba794SSrinivas Kandagatla 	u8 *p, *b;
116469aba794SSrinivas Kandagatla 	int i, bit_offset = cell->bit_offset;
116569aba794SSrinivas Kandagatla 
116669aba794SSrinivas Kandagatla 	p = b = buf;
116769aba794SSrinivas Kandagatla 	if (bit_offset) {
116869aba794SSrinivas Kandagatla 		/* First shift */
116969aba794SSrinivas Kandagatla 		*b++ >>= bit_offset;
117069aba794SSrinivas Kandagatla 
117169aba794SSrinivas Kandagatla 		/* setup rest of the bytes if any */
117269aba794SSrinivas Kandagatla 		for (i = 1; i < cell->bytes; i++) {
117369aba794SSrinivas Kandagatla 			/* Get bits from next byte and shift them towards msb */
117469aba794SSrinivas Kandagatla 			*p |= *b << (BITS_PER_BYTE - bit_offset);
117569aba794SSrinivas Kandagatla 
117669aba794SSrinivas Kandagatla 			p = b;
117769aba794SSrinivas Kandagatla 			*b++ >>= bit_offset;
117869aba794SSrinivas Kandagatla 		}
117969aba794SSrinivas Kandagatla 
118069aba794SSrinivas Kandagatla 		/* result fits in less bytes */
118169aba794SSrinivas Kandagatla 		if (cell->bytes != DIV_ROUND_UP(cell->nbits, BITS_PER_BYTE))
118269aba794SSrinivas Kandagatla 			*p-- = 0;
118369aba794SSrinivas Kandagatla 	}
118469aba794SSrinivas Kandagatla 	/* clear msb bits if any leftover in the last byte */
118569aba794SSrinivas Kandagatla 	*p &= GENMASK((cell->nbits%BITS_PER_BYTE) - 1, 0);
118669aba794SSrinivas Kandagatla }
118769aba794SSrinivas Kandagatla 
118869aba794SSrinivas Kandagatla static int __nvmem_cell_read(struct nvmem_device *nvmem,
118969aba794SSrinivas Kandagatla 		      struct nvmem_cell *cell,
119069aba794SSrinivas Kandagatla 		      void *buf, size_t *len)
119169aba794SSrinivas Kandagatla {
119269aba794SSrinivas Kandagatla 	int rc;
119369aba794SSrinivas Kandagatla 
1194795ddd18SSrinivas Kandagatla 	rc = nvmem_reg_read(nvmem, cell->offset, buf, cell->bytes);
119569aba794SSrinivas Kandagatla 
1196287980e4SArnd Bergmann 	if (rc)
119769aba794SSrinivas Kandagatla 		return rc;
119869aba794SSrinivas Kandagatla 
119969aba794SSrinivas Kandagatla 	/* shift bits in-place */
1200cbf854abSAxel Lin 	if (cell->bit_offset || cell->nbits)
120169aba794SSrinivas Kandagatla 		nvmem_shift_read_buffer_in_place(cell, buf);
120269aba794SSrinivas Kandagatla 
12033b4a6877SVivek Gautam 	if (len)
120469aba794SSrinivas Kandagatla 		*len = cell->bytes;
120569aba794SSrinivas Kandagatla 
120669aba794SSrinivas Kandagatla 	return 0;
120769aba794SSrinivas Kandagatla }
120869aba794SSrinivas Kandagatla 
120969aba794SSrinivas Kandagatla /**
121069aba794SSrinivas Kandagatla  * nvmem_cell_read() - Read a given nvmem cell
121169aba794SSrinivas Kandagatla  *
121269aba794SSrinivas Kandagatla  * @cell: nvmem cell to be read.
12133b4a6877SVivek Gautam  * @len: pointer to length of cell which will be populated on successful read;
12143b4a6877SVivek Gautam  *	 can be NULL.
121569aba794SSrinivas Kandagatla  *
1216b577fafcSBrian Norris  * Return: ERR_PTR() on error or a valid pointer to a buffer on success. The
1217b577fafcSBrian Norris  * buffer should be freed by the consumer with a kfree().
121869aba794SSrinivas Kandagatla  */
121969aba794SSrinivas Kandagatla void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len)
122069aba794SSrinivas Kandagatla {
122169aba794SSrinivas Kandagatla 	struct nvmem_device *nvmem = cell->nvmem;
122269aba794SSrinivas Kandagatla 	u8 *buf;
122369aba794SSrinivas Kandagatla 	int rc;
122469aba794SSrinivas Kandagatla 
1225795ddd18SSrinivas Kandagatla 	if (!nvmem)
122669aba794SSrinivas Kandagatla 		return ERR_PTR(-EINVAL);
122769aba794SSrinivas Kandagatla 
122869aba794SSrinivas Kandagatla 	buf = kzalloc(cell->bytes, GFP_KERNEL);
122969aba794SSrinivas Kandagatla 	if (!buf)
123069aba794SSrinivas Kandagatla 		return ERR_PTR(-ENOMEM);
123169aba794SSrinivas Kandagatla 
123269aba794SSrinivas Kandagatla 	rc = __nvmem_cell_read(nvmem, cell, buf, len);
1233287980e4SArnd Bergmann 	if (rc) {
123469aba794SSrinivas Kandagatla 		kfree(buf);
123569aba794SSrinivas Kandagatla 		return ERR_PTR(rc);
123669aba794SSrinivas Kandagatla 	}
123769aba794SSrinivas Kandagatla 
123869aba794SSrinivas Kandagatla 	return buf;
123969aba794SSrinivas Kandagatla }
124069aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_read);
124169aba794SSrinivas Kandagatla 
1242f7c04f16SMasahiro Yamada static void *nvmem_cell_prepare_write_buffer(struct nvmem_cell *cell,
124369aba794SSrinivas Kandagatla 					     u8 *_buf, int len)
124469aba794SSrinivas Kandagatla {
124569aba794SSrinivas Kandagatla 	struct nvmem_device *nvmem = cell->nvmem;
124669aba794SSrinivas Kandagatla 	int i, rc, nbits, bit_offset = cell->bit_offset;
124769aba794SSrinivas Kandagatla 	u8 v, *p, *buf, *b, pbyte, pbits;
124869aba794SSrinivas Kandagatla 
124969aba794SSrinivas Kandagatla 	nbits = cell->nbits;
125069aba794SSrinivas Kandagatla 	buf = kzalloc(cell->bytes, GFP_KERNEL);
125169aba794SSrinivas Kandagatla 	if (!buf)
125269aba794SSrinivas Kandagatla 		return ERR_PTR(-ENOMEM);
125369aba794SSrinivas Kandagatla 
125469aba794SSrinivas Kandagatla 	memcpy(buf, _buf, len);
125569aba794SSrinivas Kandagatla 	p = b = buf;
125669aba794SSrinivas Kandagatla 
125769aba794SSrinivas Kandagatla 	if (bit_offset) {
125869aba794SSrinivas Kandagatla 		pbyte = *b;
125969aba794SSrinivas Kandagatla 		*b <<= bit_offset;
126069aba794SSrinivas Kandagatla 
126169aba794SSrinivas Kandagatla 		/* setup the first byte with lsb bits from nvmem */
1262795ddd18SSrinivas Kandagatla 		rc = nvmem_reg_read(nvmem, cell->offset, &v, 1);
126350808bfcSMathieu Malaterre 		if (rc)
126450808bfcSMathieu Malaterre 			goto err;
126569aba794SSrinivas Kandagatla 		*b++ |= GENMASK(bit_offset - 1, 0) & v;
126669aba794SSrinivas Kandagatla 
126769aba794SSrinivas Kandagatla 		/* setup rest of the byte if any */
126869aba794SSrinivas Kandagatla 		for (i = 1; i < cell->bytes; i++) {
126969aba794SSrinivas Kandagatla 			/* Get last byte bits and shift them towards lsb */
127069aba794SSrinivas Kandagatla 			pbits = pbyte >> (BITS_PER_BYTE - 1 - bit_offset);
127169aba794SSrinivas Kandagatla 			pbyte = *b;
127269aba794SSrinivas Kandagatla 			p = b;
127369aba794SSrinivas Kandagatla 			*b <<= bit_offset;
127469aba794SSrinivas Kandagatla 			*b++ |= pbits;
127569aba794SSrinivas Kandagatla 		}
127669aba794SSrinivas Kandagatla 	}
127769aba794SSrinivas Kandagatla 
127869aba794SSrinivas Kandagatla 	/* if it's not end on byte boundary */
127969aba794SSrinivas Kandagatla 	if ((nbits + bit_offset) % BITS_PER_BYTE) {
128069aba794SSrinivas Kandagatla 		/* setup the last byte with msb bits from nvmem */
1281795ddd18SSrinivas Kandagatla 		rc = nvmem_reg_read(nvmem,
128269aba794SSrinivas Kandagatla 				    cell->offset + cell->bytes - 1, &v, 1);
128350808bfcSMathieu Malaterre 		if (rc)
128450808bfcSMathieu Malaterre 			goto err;
128569aba794SSrinivas Kandagatla 		*p |= GENMASK(7, (nbits + bit_offset) % BITS_PER_BYTE) & v;
128669aba794SSrinivas Kandagatla 
128769aba794SSrinivas Kandagatla 	}
128869aba794SSrinivas Kandagatla 
128969aba794SSrinivas Kandagatla 	return buf;
129050808bfcSMathieu Malaterre err:
129150808bfcSMathieu Malaterre 	kfree(buf);
129250808bfcSMathieu Malaterre 	return ERR_PTR(rc);
129369aba794SSrinivas Kandagatla }
129469aba794SSrinivas Kandagatla 
129569aba794SSrinivas Kandagatla /**
129669aba794SSrinivas Kandagatla  * nvmem_cell_write() - Write to a given nvmem cell
129769aba794SSrinivas Kandagatla  *
129869aba794SSrinivas Kandagatla  * @cell: nvmem cell to be written.
129969aba794SSrinivas Kandagatla  * @buf: Buffer to be written.
130069aba794SSrinivas Kandagatla  * @len: length of buffer to be written to nvmem cell.
130169aba794SSrinivas Kandagatla  *
130269aba794SSrinivas Kandagatla  * Return: length of bytes written or negative on failure.
130369aba794SSrinivas Kandagatla  */
130469aba794SSrinivas Kandagatla int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len)
130569aba794SSrinivas Kandagatla {
130669aba794SSrinivas Kandagatla 	struct nvmem_device *nvmem = cell->nvmem;
130769aba794SSrinivas Kandagatla 	int rc;
130869aba794SSrinivas Kandagatla 
1309795ddd18SSrinivas Kandagatla 	if (!nvmem || nvmem->read_only ||
131069aba794SSrinivas Kandagatla 	    (cell->bit_offset == 0 && len != cell->bytes))
131169aba794SSrinivas Kandagatla 		return -EINVAL;
131269aba794SSrinivas Kandagatla 
131369aba794SSrinivas Kandagatla 	if (cell->bit_offset || cell->nbits) {
131469aba794SSrinivas Kandagatla 		buf = nvmem_cell_prepare_write_buffer(cell, buf, len);
131569aba794SSrinivas Kandagatla 		if (IS_ERR(buf))
131669aba794SSrinivas Kandagatla 			return PTR_ERR(buf);
131769aba794SSrinivas Kandagatla 	}
131869aba794SSrinivas Kandagatla 
1319795ddd18SSrinivas Kandagatla 	rc = nvmem_reg_write(nvmem, cell->offset, buf, cell->bytes);
132069aba794SSrinivas Kandagatla 
132169aba794SSrinivas Kandagatla 	/* free the tmp buffer */
1322ace22170SAxel Lin 	if (cell->bit_offset || cell->nbits)
132369aba794SSrinivas Kandagatla 		kfree(buf);
132469aba794SSrinivas Kandagatla 
1325287980e4SArnd Bergmann 	if (rc)
132669aba794SSrinivas Kandagatla 		return rc;
132769aba794SSrinivas Kandagatla 
132869aba794SSrinivas Kandagatla 	return len;
132969aba794SSrinivas Kandagatla }
133069aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_write);
133169aba794SSrinivas Kandagatla 
1332e2a5402eSSrinivas Kandagatla /**
1333d026d70aSLeonard Crestez  * nvmem_cell_read_u32() - Read a cell value as an u32
1334d026d70aSLeonard Crestez  *
1335d026d70aSLeonard Crestez  * @dev: Device that requests the nvmem cell.
1336d026d70aSLeonard Crestez  * @cell_id: Name of nvmem cell to read.
1337d026d70aSLeonard Crestez  * @val: pointer to output value.
1338d026d70aSLeonard Crestez  *
1339d026d70aSLeonard Crestez  * Return: 0 on success or negative errno.
1340d026d70aSLeonard Crestez  */
1341d026d70aSLeonard Crestez int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val)
1342d026d70aSLeonard Crestez {
1343d026d70aSLeonard Crestez 	struct nvmem_cell *cell;
1344d026d70aSLeonard Crestez 	void *buf;
1345d026d70aSLeonard Crestez 	size_t len;
1346d026d70aSLeonard Crestez 
1347d026d70aSLeonard Crestez 	cell = nvmem_cell_get(dev, cell_id);
1348d026d70aSLeonard Crestez 	if (IS_ERR(cell))
1349d026d70aSLeonard Crestez 		return PTR_ERR(cell);
1350d026d70aSLeonard Crestez 
1351d026d70aSLeonard Crestez 	buf = nvmem_cell_read(cell, &len);
1352d026d70aSLeonard Crestez 	if (IS_ERR(buf)) {
1353d026d70aSLeonard Crestez 		nvmem_cell_put(cell);
1354d026d70aSLeonard Crestez 		return PTR_ERR(buf);
1355d026d70aSLeonard Crestez 	}
1356d026d70aSLeonard Crestez 	if (len != sizeof(*val)) {
1357d026d70aSLeonard Crestez 		kfree(buf);
1358d026d70aSLeonard Crestez 		nvmem_cell_put(cell);
1359d026d70aSLeonard Crestez 		return -EINVAL;
1360d026d70aSLeonard Crestez 	}
1361d026d70aSLeonard Crestez 	memcpy(val, buf, sizeof(*val));
1362d026d70aSLeonard Crestez 
1363d026d70aSLeonard Crestez 	kfree(buf);
1364d026d70aSLeonard Crestez 	nvmem_cell_put(cell);
1365d026d70aSLeonard Crestez 	return 0;
1366d026d70aSLeonard Crestez }
1367d026d70aSLeonard Crestez EXPORT_SYMBOL_GPL(nvmem_cell_read_u32);
1368d026d70aSLeonard Crestez 
1369d026d70aSLeonard Crestez /**
1370e2a5402eSSrinivas Kandagatla  * nvmem_device_cell_read() - Read a given nvmem device and cell
1371e2a5402eSSrinivas Kandagatla  *
1372e2a5402eSSrinivas Kandagatla  * @nvmem: nvmem device to read from.
1373e2a5402eSSrinivas Kandagatla  * @info: nvmem cell info to be read.
1374e2a5402eSSrinivas Kandagatla  * @buf: buffer pointer which will be populated on successful read.
1375e2a5402eSSrinivas Kandagatla  *
1376e2a5402eSSrinivas Kandagatla  * Return: length of successful bytes read on success and negative
1377e2a5402eSSrinivas Kandagatla  * error code on error.
1378e2a5402eSSrinivas Kandagatla  */
1379e2a5402eSSrinivas Kandagatla ssize_t nvmem_device_cell_read(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 	ssize_t len;
1385e2a5402eSSrinivas Kandagatla 
1386795ddd18SSrinivas Kandagatla 	if (!nvmem)
1387e2a5402eSSrinivas Kandagatla 		return -EINVAL;
1388e2a5402eSSrinivas Kandagatla 
1389e2a5402eSSrinivas Kandagatla 	rc = nvmem_cell_info_to_nvmem_cell(nvmem, info, &cell);
1390287980e4SArnd Bergmann 	if (rc)
1391e2a5402eSSrinivas Kandagatla 		return rc;
1392e2a5402eSSrinivas Kandagatla 
1393e2a5402eSSrinivas Kandagatla 	rc = __nvmem_cell_read(nvmem, &cell, buf, &len);
1394287980e4SArnd Bergmann 	if (rc)
1395e2a5402eSSrinivas Kandagatla 		return rc;
1396e2a5402eSSrinivas Kandagatla 
1397e2a5402eSSrinivas Kandagatla 	return len;
1398e2a5402eSSrinivas Kandagatla }
1399e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_cell_read);
1400e2a5402eSSrinivas Kandagatla 
1401e2a5402eSSrinivas Kandagatla /**
1402e2a5402eSSrinivas Kandagatla  * nvmem_device_cell_write() - Write cell to a given nvmem device
1403e2a5402eSSrinivas Kandagatla  *
1404e2a5402eSSrinivas Kandagatla  * @nvmem: nvmem device to be written to.
140529143268SVivek Gautam  * @info: nvmem cell info to be written.
1406e2a5402eSSrinivas Kandagatla  * @buf: buffer to be written to cell.
1407e2a5402eSSrinivas Kandagatla  *
1408e2a5402eSSrinivas Kandagatla  * Return: length of bytes written or negative error code on failure.
140948f63a2cSBartosz Golaszewski  */
1410e2a5402eSSrinivas Kandagatla int nvmem_device_cell_write(struct nvmem_device *nvmem,
1411e2a5402eSSrinivas Kandagatla 			    struct nvmem_cell_info *info, void *buf)
1412e2a5402eSSrinivas Kandagatla {
1413e2a5402eSSrinivas Kandagatla 	struct nvmem_cell cell;
1414e2a5402eSSrinivas Kandagatla 	int rc;
1415e2a5402eSSrinivas Kandagatla 
1416795ddd18SSrinivas Kandagatla 	if (!nvmem)
1417e2a5402eSSrinivas Kandagatla 		return -EINVAL;
1418e2a5402eSSrinivas Kandagatla 
1419e2a5402eSSrinivas Kandagatla 	rc = nvmem_cell_info_to_nvmem_cell(nvmem, info, &cell);
1420287980e4SArnd Bergmann 	if (rc)
1421e2a5402eSSrinivas Kandagatla 		return rc;
1422e2a5402eSSrinivas Kandagatla 
1423e2a5402eSSrinivas Kandagatla 	return nvmem_cell_write(&cell, buf, cell.bytes);
1424e2a5402eSSrinivas Kandagatla }
1425e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_cell_write);
1426e2a5402eSSrinivas Kandagatla 
1427e2a5402eSSrinivas Kandagatla /**
1428e2a5402eSSrinivas Kandagatla  * nvmem_device_read() - Read from a given nvmem device
1429e2a5402eSSrinivas Kandagatla  *
1430e2a5402eSSrinivas Kandagatla  * @nvmem: nvmem device to read from.
1431e2a5402eSSrinivas Kandagatla  * @offset: offset in nvmem device.
1432e2a5402eSSrinivas Kandagatla  * @bytes: number of bytes to read.
1433e2a5402eSSrinivas Kandagatla  * @buf: buffer pointer which will be populated on successful read.
1434e2a5402eSSrinivas Kandagatla  *
1435e2a5402eSSrinivas Kandagatla  * Return: length of successful bytes read on success and negative
1436e2a5402eSSrinivas Kandagatla  * error code on error.
1437e2a5402eSSrinivas Kandagatla  */
1438e2a5402eSSrinivas Kandagatla int nvmem_device_read(struct nvmem_device *nvmem,
1439e2a5402eSSrinivas Kandagatla 		      unsigned int offset,
1440e2a5402eSSrinivas Kandagatla 		      size_t bytes, void *buf)
1441e2a5402eSSrinivas Kandagatla {
1442e2a5402eSSrinivas Kandagatla 	int rc;
1443e2a5402eSSrinivas Kandagatla 
1444795ddd18SSrinivas Kandagatla 	if (!nvmem)
1445e2a5402eSSrinivas Kandagatla 		return -EINVAL;
1446e2a5402eSSrinivas Kandagatla 
1447795ddd18SSrinivas Kandagatla 	rc = nvmem_reg_read(nvmem, offset, buf, bytes);
1448e2a5402eSSrinivas Kandagatla 
1449287980e4SArnd Bergmann 	if (rc)
1450e2a5402eSSrinivas Kandagatla 		return rc;
1451e2a5402eSSrinivas Kandagatla 
1452e2a5402eSSrinivas Kandagatla 	return bytes;
1453e2a5402eSSrinivas Kandagatla }
1454e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_read);
1455e2a5402eSSrinivas Kandagatla 
1456e2a5402eSSrinivas Kandagatla /**
1457e2a5402eSSrinivas Kandagatla  * nvmem_device_write() - Write cell to a given nvmem device
1458e2a5402eSSrinivas Kandagatla  *
1459e2a5402eSSrinivas Kandagatla  * @nvmem: nvmem device to be written to.
1460e2a5402eSSrinivas Kandagatla  * @offset: offset in nvmem device.
1461e2a5402eSSrinivas Kandagatla  * @bytes: number of bytes to write.
1462e2a5402eSSrinivas Kandagatla  * @buf: buffer to be written.
1463e2a5402eSSrinivas Kandagatla  *
1464e2a5402eSSrinivas Kandagatla  * Return: length of bytes written or negative error code on failure.
146548f63a2cSBartosz Golaszewski  */
1466e2a5402eSSrinivas Kandagatla int nvmem_device_write(struct nvmem_device *nvmem,
1467e2a5402eSSrinivas Kandagatla 		       unsigned int offset,
1468e2a5402eSSrinivas Kandagatla 		       size_t bytes, void *buf)
1469e2a5402eSSrinivas Kandagatla {
1470e2a5402eSSrinivas Kandagatla 	int rc;
1471e2a5402eSSrinivas Kandagatla 
1472795ddd18SSrinivas Kandagatla 	if (!nvmem)
1473e2a5402eSSrinivas Kandagatla 		return -EINVAL;
1474e2a5402eSSrinivas Kandagatla 
1475795ddd18SSrinivas Kandagatla 	rc = nvmem_reg_write(nvmem, offset, buf, bytes);
1476e2a5402eSSrinivas Kandagatla 
1477287980e4SArnd Bergmann 	if (rc)
1478e2a5402eSSrinivas Kandagatla 		return rc;
1479e2a5402eSSrinivas Kandagatla 
1480e2a5402eSSrinivas Kandagatla 
1481e2a5402eSSrinivas Kandagatla 	return bytes;
1482e2a5402eSSrinivas Kandagatla }
1483e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_write);
1484e2a5402eSSrinivas Kandagatla 
1485d7b9fd16SBartosz Golaszewski /**
1486b985f4cbSBartosz Golaszewski  * nvmem_add_cell_table() - register a table of cell info entries
1487b985f4cbSBartosz Golaszewski  *
1488b985f4cbSBartosz Golaszewski  * @table: table of cell info entries
1489b985f4cbSBartosz Golaszewski  */
1490b985f4cbSBartosz Golaszewski void nvmem_add_cell_table(struct nvmem_cell_table *table)
1491b985f4cbSBartosz Golaszewski {
1492b985f4cbSBartosz Golaszewski 	mutex_lock(&nvmem_cell_mutex);
1493b985f4cbSBartosz Golaszewski 	list_add_tail(&table->node, &nvmem_cell_tables);
1494b985f4cbSBartosz Golaszewski 	mutex_unlock(&nvmem_cell_mutex);
1495b985f4cbSBartosz Golaszewski }
1496b985f4cbSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_add_cell_table);
1497b985f4cbSBartosz Golaszewski 
1498b985f4cbSBartosz Golaszewski /**
1499b985f4cbSBartosz Golaszewski  * nvmem_del_cell_table() - remove a previously registered cell info table
1500b985f4cbSBartosz Golaszewski  *
1501b985f4cbSBartosz Golaszewski  * @table: table of cell info entries
1502b985f4cbSBartosz Golaszewski  */
1503b985f4cbSBartosz Golaszewski void nvmem_del_cell_table(struct nvmem_cell_table *table)
1504b985f4cbSBartosz Golaszewski {
1505b985f4cbSBartosz Golaszewski 	mutex_lock(&nvmem_cell_mutex);
1506b985f4cbSBartosz Golaszewski 	list_del(&table->node);
1507b985f4cbSBartosz Golaszewski 	mutex_unlock(&nvmem_cell_mutex);
1508b985f4cbSBartosz Golaszewski }
1509b985f4cbSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_del_cell_table);
1510b985f4cbSBartosz Golaszewski 
1511b985f4cbSBartosz Golaszewski /**
1512506157beSBartosz Golaszewski  * nvmem_add_cell_lookups() - register a list of cell lookup entries
1513506157beSBartosz Golaszewski  *
1514506157beSBartosz Golaszewski  * @entries: array of cell lookup entries
1515506157beSBartosz Golaszewski  * @nentries: number of cell lookup entries in the array
1516506157beSBartosz Golaszewski  */
1517506157beSBartosz Golaszewski void nvmem_add_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries)
1518506157beSBartosz Golaszewski {
1519506157beSBartosz Golaszewski 	int i;
1520506157beSBartosz Golaszewski 
1521506157beSBartosz Golaszewski 	mutex_lock(&nvmem_lookup_mutex);
1522506157beSBartosz Golaszewski 	for (i = 0; i < nentries; i++)
1523506157beSBartosz Golaszewski 		list_add_tail(&entries[i].node, &nvmem_lookup_list);
1524506157beSBartosz Golaszewski 	mutex_unlock(&nvmem_lookup_mutex);
1525506157beSBartosz Golaszewski }
1526506157beSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_add_cell_lookups);
1527506157beSBartosz Golaszewski 
1528506157beSBartosz Golaszewski /**
1529506157beSBartosz Golaszewski  * nvmem_del_cell_lookups() - remove a list of previously added cell lookup
1530506157beSBartosz Golaszewski  *                            entries
1531506157beSBartosz Golaszewski  *
1532506157beSBartosz Golaszewski  * @entries: array of cell lookup entries
1533506157beSBartosz Golaszewski  * @nentries: number of cell lookup entries in the array
1534506157beSBartosz Golaszewski  */
1535506157beSBartosz Golaszewski void nvmem_del_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries)
1536506157beSBartosz Golaszewski {
1537506157beSBartosz Golaszewski 	int i;
1538506157beSBartosz Golaszewski 
1539506157beSBartosz Golaszewski 	mutex_lock(&nvmem_lookup_mutex);
1540506157beSBartosz Golaszewski 	for (i = 0; i < nentries; i++)
1541506157beSBartosz Golaszewski 		list_del(&entries[i].node);
1542506157beSBartosz Golaszewski 	mutex_unlock(&nvmem_lookup_mutex);
1543506157beSBartosz Golaszewski }
1544506157beSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_del_cell_lookups);
1545506157beSBartosz Golaszewski 
1546506157beSBartosz Golaszewski /**
1547d7b9fd16SBartosz Golaszewski  * nvmem_dev_name() - Get the name of a given nvmem device.
1548d7b9fd16SBartosz Golaszewski  *
1549d7b9fd16SBartosz Golaszewski  * @nvmem: nvmem device.
1550d7b9fd16SBartosz Golaszewski  *
1551d7b9fd16SBartosz Golaszewski  * Return: name of the nvmem device.
1552d7b9fd16SBartosz Golaszewski  */
1553d7b9fd16SBartosz Golaszewski const char *nvmem_dev_name(struct nvmem_device *nvmem)
1554d7b9fd16SBartosz Golaszewski {
1555d7b9fd16SBartosz Golaszewski 	return dev_name(&nvmem->dev);
1556d7b9fd16SBartosz Golaszewski }
1557d7b9fd16SBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_dev_name);
1558d7b9fd16SBartosz Golaszewski 
1559eace75cfSSrinivas Kandagatla static int __init nvmem_init(void)
1560eace75cfSSrinivas Kandagatla {
1561eace75cfSSrinivas Kandagatla 	return bus_register(&nvmem_bus_type);
1562eace75cfSSrinivas Kandagatla }
1563eace75cfSSrinivas Kandagatla 
1564eace75cfSSrinivas Kandagatla static void __exit nvmem_exit(void)
1565eace75cfSSrinivas Kandagatla {
1566eace75cfSSrinivas Kandagatla 	bus_unregister(&nvmem_bus_type);
1567eace75cfSSrinivas Kandagatla }
1568eace75cfSSrinivas Kandagatla 
1569eace75cfSSrinivas Kandagatla subsys_initcall(nvmem_init);
1570eace75cfSSrinivas Kandagatla module_exit(nvmem_exit);
1571eace75cfSSrinivas Kandagatla 
1572eace75cfSSrinivas Kandagatla MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org");
1573eace75cfSSrinivas Kandagatla MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com");
1574eace75cfSSrinivas Kandagatla MODULE_DESCRIPTION("nvmem Driver Core");
1575eace75cfSSrinivas Kandagatla MODULE_LICENSE("GPL v2");
1576