xref: /linux/drivers/nvmem/core.c (revision 1a371190a375f98c9b106f758ea41558c3f92556)
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>
182a127da4SKhouloud Touil #include <linux/gpio/consumer.h>
19eace75cfSSrinivas Kandagatla #include <linux/of.h>
20eace75cfSSrinivas Kandagatla #include <linux/slab.h>
2184400305SSrinivas Kandagatla 
22ec9c08a1SMiquel Raynal #include "internals.h"
2384400305SSrinivas Kandagatla 
2484400305SSrinivas Kandagatla #define to_nvmem_device(d) container_of(d, struct nvmem_device, dev)
2584400305SSrinivas Kandagatla 
2684400305SSrinivas Kandagatla #define FLAG_COMPAT		BIT(0)
277ae6478bSSrinivas Kandagatla struct nvmem_cell_entry {
28eace75cfSSrinivas Kandagatla 	const char		*name;
29eace75cfSSrinivas Kandagatla 	int			offset;
3055d4980cSRafał Miłecki 	size_t			raw_len;
31eace75cfSSrinivas Kandagatla 	int			bytes;
32eace75cfSSrinivas Kandagatla 	int			bit_offset;
33eace75cfSSrinivas Kandagatla 	int			nbits;
34345ec382SMichael Walle 	nvmem_cell_post_process_t read_post_process;
358a134fd9SMichael Walle 	void			*priv;
360749aa25SSrinivas Kandagatla 	struct device_node	*np;
37eace75cfSSrinivas Kandagatla 	struct nvmem_device	*nvmem;
38eace75cfSSrinivas Kandagatla 	struct list_head	node;
39eace75cfSSrinivas Kandagatla };
40eace75cfSSrinivas Kandagatla 
417ae6478bSSrinivas Kandagatla struct nvmem_cell {
427ae6478bSSrinivas Kandagatla 	struct nvmem_cell_entry *entry;
437ae6478bSSrinivas Kandagatla 	const char		*id;
445d8e6e6cSMichael Walle 	int			index;
457ae6478bSSrinivas Kandagatla };
467ae6478bSSrinivas Kandagatla 
47eace75cfSSrinivas Kandagatla static DEFINE_MUTEX(nvmem_mutex);
48eace75cfSSrinivas Kandagatla static DEFINE_IDA(nvmem_ida);
49eace75cfSSrinivas Kandagatla 
50b985f4cbSBartosz Golaszewski static DEFINE_MUTEX(nvmem_cell_mutex);
51b985f4cbSBartosz Golaszewski static LIST_HEAD(nvmem_cell_tables);
52b985f4cbSBartosz Golaszewski 
53506157beSBartosz Golaszewski static DEFINE_MUTEX(nvmem_lookup_mutex);
54506157beSBartosz Golaszewski static LIST_HEAD(nvmem_lookup_list);
55506157beSBartosz Golaszewski 
56bee1138bSBartosz Golaszewski static BLOCKING_NOTIFIER_HEAD(nvmem_notifier);
57bee1138bSBartosz Golaszewski 
__nvmem_reg_read(struct nvmem_device * nvmem,unsigned int offset,void * val,size_t bytes)58fd3bb8f5SEvan Green static int __nvmem_reg_read(struct nvmem_device *nvmem, unsigned int offset,
59b96fc541SMichael Auchter 			    void *val, size_t bytes)
60b96fc541SMichael Auchter {
61b96fc541SMichael Auchter 	if (nvmem->reg_read)
62b96fc541SMichael Auchter 		return nvmem->reg_read(nvmem->priv, offset, val, bytes);
63b96fc541SMichael Auchter 
64b96fc541SMichael Auchter 	return -EINVAL;
65b96fc541SMichael Auchter }
66b96fc541SMichael Auchter 
__nvmem_reg_write(struct nvmem_device * nvmem,unsigned int offset,void * val,size_t bytes)67fd3bb8f5SEvan Green static int __nvmem_reg_write(struct nvmem_device *nvmem, unsigned int offset,
68b96fc541SMichael Auchter 			     void *val, size_t bytes)
69b96fc541SMichael Auchter {
70b96fc541SMichael Auchter 	int ret;
71b96fc541SMichael Auchter 
72b96fc541SMichael Auchter 	if (nvmem->reg_write) {
73b96fc541SMichael Auchter 		gpiod_set_value_cansleep(nvmem->wp_gpio, 0);
74b96fc541SMichael Auchter 		ret = nvmem->reg_write(nvmem->priv, offset, val, bytes);
75b96fc541SMichael Auchter 		gpiod_set_value_cansleep(nvmem->wp_gpio, 1);
76b96fc541SMichael Auchter 		return ret;
77b96fc541SMichael Auchter 	}
78b96fc541SMichael Auchter 
79b96fc541SMichael Auchter 	return -EINVAL;
80b96fc541SMichael Auchter }
81b96fc541SMichael Auchter 
nvmem_access_with_keepouts(struct nvmem_device * nvmem,unsigned int offset,void * val,size_t bytes,int write)82fd3bb8f5SEvan Green static int nvmem_access_with_keepouts(struct nvmem_device *nvmem,
83fd3bb8f5SEvan Green 				      unsigned int offset, void *val,
84fd3bb8f5SEvan Green 				      size_t bytes, int write)
85fd3bb8f5SEvan Green {
86fd3bb8f5SEvan Green 
87fd3bb8f5SEvan Green 	unsigned int end = offset + bytes;
88fd3bb8f5SEvan Green 	unsigned int kend, ksize;
89fd3bb8f5SEvan Green 	const struct nvmem_keepout *keepout = nvmem->keepout;
90fd3bb8f5SEvan Green 	const struct nvmem_keepout *keepoutend = keepout + nvmem->nkeepout;
91fd3bb8f5SEvan Green 	int rc;
92fd3bb8f5SEvan Green 
93fd3bb8f5SEvan Green 	/*
94fd3bb8f5SEvan Green 	 * Skip all keepouts before the range being accessed.
95fd3bb8f5SEvan Green 	 * Keepouts are sorted.
96fd3bb8f5SEvan Green 	 */
97fd3bb8f5SEvan Green 	while ((keepout < keepoutend) && (keepout->end <= offset))
98fd3bb8f5SEvan Green 		keepout++;
99fd3bb8f5SEvan Green 
100fd3bb8f5SEvan Green 	while ((offset < end) && (keepout < keepoutend)) {
101fd3bb8f5SEvan Green 		/* Access the valid portion before the keepout. */
102fd3bb8f5SEvan Green 		if (offset < keepout->start) {
103fd3bb8f5SEvan Green 			kend = min(end, keepout->start);
104fd3bb8f5SEvan Green 			ksize = kend - offset;
105fd3bb8f5SEvan Green 			if (write)
106fd3bb8f5SEvan Green 				rc = __nvmem_reg_write(nvmem, offset, val, ksize);
107fd3bb8f5SEvan Green 			else
108fd3bb8f5SEvan Green 				rc = __nvmem_reg_read(nvmem, offset, val, ksize);
109fd3bb8f5SEvan Green 
110fd3bb8f5SEvan Green 			if (rc)
111fd3bb8f5SEvan Green 				return rc;
112fd3bb8f5SEvan Green 
113fd3bb8f5SEvan Green 			offset += ksize;
114fd3bb8f5SEvan Green 			val += ksize;
115fd3bb8f5SEvan Green 		}
116fd3bb8f5SEvan Green 
117fd3bb8f5SEvan Green 		/*
118fd3bb8f5SEvan Green 		 * Now we're aligned to the start of this keepout zone. Go
119fd3bb8f5SEvan Green 		 * through it.
120fd3bb8f5SEvan Green 		 */
121fd3bb8f5SEvan Green 		kend = min(end, keepout->end);
122fd3bb8f5SEvan Green 		ksize = kend - offset;
123fd3bb8f5SEvan Green 		if (!write)
124fd3bb8f5SEvan Green 			memset(val, keepout->value, ksize);
125fd3bb8f5SEvan Green 
126fd3bb8f5SEvan Green 		val += ksize;
127fd3bb8f5SEvan Green 		offset += ksize;
128fd3bb8f5SEvan Green 		keepout++;
129fd3bb8f5SEvan Green 	}
130fd3bb8f5SEvan Green 
131fd3bb8f5SEvan Green 	/*
132fd3bb8f5SEvan Green 	 * If we ran out of keepouts but there's still stuff to do, send it
133fd3bb8f5SEvan Green 	 * down directly
134fd3bb8f5SEvan Green 	 */
135fd3bb8f5SEvan Green 	if (offset < end) {
136fd3bb8f5SEvan Green 		ksize = end - offset;
137fd3bb8f5SEvan Green 		if (write)
138fd3bb8f5SEvan Green 			return __nvmem_reg_write(nvmem, offset, val, ksize);
139fd3bb8f5SEvan Green 		else
140fd3bb8f5SEvan Green 			return __nvmem_reg_read(nvmem, offset, val, ksize);
141fd3bb8f5SEvan Green 	}
142fd3bb8f5SEvan Green 
143fd3bb8f5SEvan Green 	return 0;
144fd3bb8f5SEvan Green }
145fd3bb8f5SEvan Green 
nvmem_reg_read(struct nvmem_device * nvmem,unsigned int offset,void * val,size_t bytes)146fd3bb8f5SEvan Green static int nvmem_reg_read(struct nvmem_device *nvmem, unsigned int offset,
147fd3bb8f5SEvan Green 			  void *val, size_t bytes)
148fd3bb8f5SEvan Green {
149fd3bb8f5SEvan Green 	if (!nvmem->nkeepout)
150fd3bb8f5SEvan Green 		return __nvmem_reg_read(nvmem, offset, val, bytes);
151fd3bb8f5SEvan Green 
152fd3bb8f5SEvan Green 	return nvmem_access_with_keepouts(nvmem, offset, val, bytes, false);
153fd3bb8f5SEvan Green }
154fd3bb8f5SEvan Green 
nvmem_reg_write(struct nvmem_device * nvmem,unsigned int offset,void * val,size_t bytes)155fd3bb8f5SEvan Green static int nvmem_reg_write(struct nvmem_device *nvmem, unsigned int offset,
156fd3bb8f5SEvan Green 			   void *val, size_t bytes)
157fd3bb8f5SEvan Green {
158fd3bb8f5SEvan Green 	if (!nvmem->nkeepout)
159fd3bb8f5SEvan Green 		return __nvmem_reg_write(nvmem, offset, val, bytes);
160fd3bb8f5SEvan Green 
161fd3bb8f5SEvan Green 	return nvmem_access_with_keepouts(nvmem, offset, val, bytes, true);
162fd3bb8f5SEvan Green }
163fd3bb8f5SEvan Green 
16484400305SSrinivas Kandagatla #ifdef CONFIG_NVMEM_SYSFS
16584400305SSrinivas Kandagatla static const char * const nvmem_type_str[] = {
16684400305SSrinivas Kandagatla 	[NVMEM_TYPE_UNKNOWN] = "Unknown",
16784400305SSrinivas Kandagatla 	[NVMEM_TYPE_EEPROM] = "EEPROM",
16884400305SSrinivas Kandagatla 	[NVMEM_TYPE_OTP] = "OTP",
16984400305SSrinivas Kandagatla 	[NVMEM_TYPE_BATTERY_BACKED] = "Battery backed",
170fd307a4aSJiri Prchal 	[NVMEM_TYPE_FRAM] = "FRAM",
17184400305SSrinivas Kandagatla };
17284400305SSrinivas Kandagatla 
17384400305SSrinivas Kandagatla #ifdef CONFIG_DEBUG_LOCK_ALLOC
17484400305SSrinivas Kandagatla static struct lock_class_key eeprom_lock_key;
17584400305SSrinivas Kandagatla #endif
17684400305SSrinivas Kandagatla 
type_show(struct device * dev,struct device_attribute * attr,char * buf)17784400305SSrinivas Kandagatla static ssize_t type_show(struct device *dev,
17884400305SSrinivas Kandagatla 			 struct device_attribute *attr, char *buf)
17984400305SSrinivas Kandagatla {
18084400305SSrinivas Kandagatla 	struct nvmem_device *nvmem = to_nvmem_device(dev);
18184400305SSrinivas Kandagatla 
18208c367e4SMarek Vasut 	return sysfs_emit(buf, "%s\n", nvmem_type_str[nvmem->type]);
18384400305SSrinivas Kandagatla }
18484400305SSrinivas Kandagatla 
18584400305SSrinivas Kandagatla static DEVICE_ATTR_RO(type);
18684400305SSrinivas Kandagatla 
force_ro_show(struct device * dev,struct device_attribute * attr,char * buf)1879d7eb234SMarek Vasut static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr,
1889d7eb234SMarek Vasut 			     char *buf)
1899d7eb234SMarek Vasut {
1909d7eb234SMarek Vasut 	struct nvmem_device *nvmem = to_nvmem_device(dev);
1919d7eb234SMarek Vasut 
1929d7eb234SMarek Vasut 	return sysfs_emit(buf, "%d\n", nvmem->read_only);
1939d7eb234SMarek Vasut }
1949d7eb234SMarek Vasut 
force_ro_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)1959d7eb234SMarek Vasut static ssize_t force_ro_store(struct device *dev, struct device_attribute *attr,
1969d7eb234SMarek Vasut 			      const char *buf, size_t count)
1979d7eb234SMarek Vasut {
1989d7eb234SMarek Vasut 	struct nvmem_device *nvmem = to_nvmem_device(dev);
1999d7eb234SMarek Vasut 	int ret = kstrtobool(buf, &nvmem->read_only);
2009d7eb234SMarek Vasut 
2019d7eb234SMarek Vasut 	if (ret < 0)
2029d7eb234SMarek Vasut 		return ret;
2039d7eb234SMarek Vasut 
2049d7eb234SMarek Vasut 	return count;
2059d7eb234SMarek Vasut }
2069d7eb234SMarek Vasut 
2079d7eb234SMarek Vasut static DEVICE_ATTR_RW(force_ro);
2089d7eb234SMarek Vasut 
20984400305SSrinivas Kandagatla static struct attribute *nvmem_attrs[] = {
2109d7eb234SMarek Vasut 	&dev_attr_force_ro.attr,
21184400305SSrinivas Kandagatla 	&dev_attr_type.attr,
21284400305SSrinivas Kandagatla 	NULL,
21384400305SSrinivas Kandagatla };
21484400305SSrinivas Kandagatla 
bin_attr_nvmem_read(struct file * filp,struct kobject * kobj,struct bin_attribute * attr,char * buf,loff_t pos,size_t count)21584400305SSrinivas Kandagatla static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj,
21684400305SSrinivas Kandagatla 				   struct bin_attribute *attr, char *buf,
21784400305SSrinivas Kandagatla 				   loff_t pos, size_t count)
21884400305SSrinivas Kandagatla {
21984400305SSrinivas Kandagatla 	struct device *dev;
22084400305SSrinivas Kandagatla 	struct nvmem_device *nvmem;
22184400305SSrinivas Kandagatla 	int rc;
22284400305SSrinivas Kandagatla 
22384400305SSrinivas Kandagatla 	if (attr->private)
22484400305SSrinivas Kandagatla 		dev = attr->private;
22584400305SSrinivas Kandagatla 	else
22628371cc6STian Tao 		dev = kobj_to_dev(kobj);
22784400305SSrinivas Kandagatla 	nvmem = to_nvmem_device(dev);
22884400305SSrinivas Kandagatla 
22983566715SDouglas Anderson 	if (!IS_ALIGNED(pos, nvmem->stride))
23083566715SDouglas Anderson 		return -EINVAL;
23183566715SDouglas Anderson 
23284400305SSrinivas Kandagatla 	if (count < nvmem->word_size)
23384400305SSrinivas Kandagatla 		return -EINVAL;
23484400305SSrinivas Kandagatla 
23584400305SSrinivas Kandagatla 	count = round_down(count, nvmem->word_size);
23684400305SSrinivas Kandagatla 
23784400305SSrinivas Kandagatla 	if (!nvmem->reg_read)
23884400305SSrinivas Kandagatla 		return -EPERM;
23984400305SSrinivas Kandagatla 
240b96fc541SMichael Auchter 	rc = nvmem_reg_read(nvmem, pos, buf, count);
24184400305SSrinivas Kandagatla 
24284400305SSrinivas Kandagatla 	if (rc)
24384400305SSrinivas Kandagatla 		return rc;
24484400305SSrinivas Kandagatla 
24584400305SSrinivas Kandagatla 	return count;
24684400305SSrinivas Kandagatla }
24784400305SSrinivas Kandagatla 
bin_attr_nvmem_write(struct file * filp,struct kobject * kobj,struct bin_attribute * attr,char * buf,loff_t pos,size_t count)24884400305SSrinivas Kandagatla static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj,
24984400305SSrinivas Kandagatla 				    struct bin_attribute *attr, char *buf,
25084400305SSrinivas Kandagatla 				    loff_t pos, size_t count)
25184400305SSrinivas Kandagatla {
25284400305SSrinivas Kandagatla 	struct device *dev;
25384400305SSrinivas Kandagatla 	struct nvmem_device *nvmem;
25484400305SSrinivas Kandagatla 	int rc;
25584400305SSrinivas Kandagatla 
25684400305SSrinivas Kandagatla 	if (attr->private)
25784400305SSrinivas Kandagatla 		dev = attr->private;
25884400305SSrinivas Kandagatla 	else
25928371cc6STian Tao 		dev = kobj_to_dev(kobj);
26084400305SSrinivas Kandagatla 	nvmem = to_nvmem_device(dev);
26184400305SSrinivas Kandagatla 
26283566715SDouglas Anderson 	if (!IS_ALIGNED(pos, nvmem->stride))
26383566715SDouglas Anderson 		return -EINVAL;
26483566715SDouglas Anderson 
26584400305SSrinivas Kandagatla 	if (count < nvmem->word_size)
26684400305SSrinivas Kandagatla 		return -EINVAL;
26784400305SSrinivas Kandagatla 
26884400305SSrinivas Kandagatla 	count = round_down(count, nvmem->word_size);
26984400305SSrinivas Kandagatla 
27084400305SSrinivas Kandagatla 	if (!nvmem->reg_write)
27184400305SSrinivas Kandagatla 		return -EPERM;
27284400305SSrinivas Kandagatla 
273b96fc541SMichael Auchter 	rc = nvmem_reg_write(nvmem, pos, buf, count);
27484400305SSrinivas Kandagatla 
27584400305SSrinivas Kandagatla 	if (rc)
27684400305SSrinivas Kandagatla 		return rc;
27784400305SSrinivas Kandagatla 
27884400305SSrinivas Kandagatla 	return count;
27984400305SSrinivas Kandagatla }
28084400305SSrinivas Kandagatla 
nvmem_bin_attr_get_umode(struct nvmem_device * nvmem)2812a4542e5SSrinivas Kandagatla static umode_t nvmem_bin_attr_get_umode(struct nvmem_device *nvmem)
28284400305SSrinivas Kandagatla {
28384400305SSrinivas Kandagatla 	umode_t mode = 0400;
28484400305SSrinivas Kandagatla 
28584400305SSrinivas Kandagatla 	if (!nvmem->root_only)
28684400305SSrinivas Kandagatla 		mode |= 0044;
28784400305SSrinivas Kandagatla 
28884400305SSrinivas Kandagatla 	if (!nvmem->read_only)
28984400305SSrinivas Kandagatla 		mode |= 0200;
29084400305SSrinivas Kandagatla 
29184400305SSrinivas Kandagatla 	if (!nvmem->reg_write)
29284400305SSrinivas Kandagatla 		mode &= ~0200;
29384400305SSrinivas Kandagatla 
29484400305SSrinivas Kandagatla 	if (!nvmem->reg_read)
29584400305SSrinivas Kandagatla 		mode &= ~0444;
29684400305SSrinivas Kandagatla 
29784400305SSrinivas Kandagatla 	return mode;
29884400305SSrinivas Kandagatla }
29984400305SSrinivas Kandagatla 
nvmem_bin_attr_is_visible(struct kobject * kobj,struct bin_attribute * attr,int i)3002a4542e5SSrinivas Kandagatla static umode_t nvmem_bin_attr_is_visible(struct kobject *kobj,
3012a4542e5SSrinivas Kandagatla 					 struct bin_attribute *attr, int i)
3022a4542e5SSrinivas Kandagatla {
30328371cc6STian Tao 	struct device *dev = kobj_to_dev(kobj);
3042a4542e5SSrinivas Kandagatla 	struct nvmem_device *nvmem = to_nvmem_device(dev);
3052a4542e5SSrinivas Kandagatla 
30686192251SSrinivas Kandagatla 	attr->size = nvmem->size;
30786192251SSrinivas Kandagatla 
3082a4542e5SSrinivas Kandagatla 	return nvmem_bin_attr_get_umode(nvmem);
3092a4542e5SSrinivas Kandagatla }
3102a4542e5SSrinivas Kandagatla 
nvmem_attr_is_visible(struct kobject * kobj,struct attribute * attr,int i)3119d7eb234SMarek Vasut static umode_t nvmem_attr_is_visible(struct kobject *kobj,
3129d7eb234SMarek Vasut 				     struct attribute *attr, int i)
3139d7eb234SMarek Vasut {
3149d7eb234SMarek Vasut 	struct device *dev = kobj_to_dev(kobj);
3159d7eb234SMarek Vasut 	struct nvmem_device *nvmem = to_nvmem_device(dev);
3169d7eb234SMarek Vasut 
3179d7eb234SMarek Vasut 	/*
3189d7eb234SMarek Vasut 	 * If the device has no .reg_write operation, do not allow
3199d7eb234SMarek Vasut 	 * configuration as read-write.
3209d7eb234SMarek Vasut 	 * If the device is set as read-only by configuration, it
3219d7eb234SMarek Vasut 	 * can be forced into read-write mode using the 'force_ro'
3229d7eb234SMarek Vasut 	 * attribute.
3239d7eb234SMarek Vasut 	 */
3249d7eb234SMarek Vasut 	if (attr == &dev_attr_force_ro.attr && !nvmem->reg_write)
3259d7eb234SMarek Vasut 		return 0;	/* Attribute not visible */
3269d7eb234SMarek Vasut 
3279d7eb234SMarek Vasut 	return attr->mode;
3289d7eb234SMarek Vasut }
3299d7eb234SMarek Vasut 
3300331c611SMiquel Raynal static struct nvmem_cell *nvmem_create_cell(struct nvmem_cell_entry *entry,
3310331c611SMiquel Raynal 					    const char *id, int index);
3320331c611SMiquel Raynal 
nvmem_cell_attr_read(struct file * filp,struct kobject * kobj,struct bin_attribute * attr,char * buf,loff_t pos,size_t count)3330331c611SMiquel Raynal static ssize_t nvmem_cell_attr_read(struct file *filp, struct kobject *kobj,
3340331c611SMiquel Raynal 				    struct bin_attribute *attr, char *buf,
3350331c611SMiquel Raynal 				    loff_t pos, size_t count)
3360331c611SMiquel Raynal {
3370331c611SMiquel Raynal 	struct nvmem_cell_entry *entry;
3380331c611SMiquel Raynal 	struct nvmem_cell *cell = NULL;
3390331c611SMiquel Raynal 	size_t cell_sz, read_len;
3400331c611SMiquel Raynal 	void *content;
3410331c611SMiquel Raynal 
3420331c611SMiquel Raynal 	entry = attr->private;
3430331c611SMiquel Raynal 	cell = nvmem_create_cell(entry, entry->name, 0);
3440331c611SMiquel Raynal 	if (IS_ERR(cell))
3450331c611SMiquel Raynal 		return PTR_ERR(cell);
3460331c611SMiquel Raynal 
3470331c611SMiquel Raynal 	if (!cell)
3480331c611SMiquel Raynal 		return -EINVAL;
3490331c611SMiquel Raynal 
3500331c611SMiquel Raynal 	content = nvmem_cell_read(cell, &cell_sz);
3510331c611SMiquel Raynal 	if (IS_ERR(content)) {
3520331c611SMiquel Raynal 		read_len = PTR_ERR(content);
3530331c611SMiquel Raynal 		goto destroy_cell;
3540331c611SMiquel Raynal 	}
3550331c611SMiquel Raynal 
3560331c611SMiquel Raynal 	read_len = min_t(unsigned int, cell_sz - pos, count);
3570331c611SMiquel Raynal 	memcpy(buf, content + pos, read_len);
3580331c611SMiquel Raynal 	kfree(content);
3590331c611SMiquel Raynal 
3600331c611SMiquel Raynal destroy_cell:
3610331c611SMiquel Raynal 	kfree_const(cell->id);
3620331c611SMiquel Raynal 	kfree(cell);
3630331c611SMiquel Raynal 
3640331c611SMiquel Raynal 	return read_len;
3650331c611SMiquel Raynal }
3660331c611SMiquel Raynal 
36784400305SSrinivas Kandagatla /* default read/write permissions */
36884400305SSrinivas Kandagatla static struct bin_attribute bin_attr_rw_nvmem = {
36984400305SSrinivas Kandagatla 	.attr	= {
37084400305SSrinivas Kandagatla 		.name	= "nvmem",
37184400305SSrinivas Kandagatla 		.mode	= 0644,
37284400305SSrinivas Kandagatla 	},
37384400305SSrinivas Kandagatla 	.read	= bin_attr_nvmem_read,
37484400305SSrinivas Kandagatla 	.write	= bin_attr_nvmem_write,
37584400305SSrinivas Kandagatla };
37684400305SSrinivas Kandagatla 
37784400305SSrinivas Kandagatla static struct bin_attribute *nvmem_bin_attributes[] = {
37884400305SSrinivas Kandagatla 	&bin_attr_rw_nvmem,
37984400305SSrinivas Kandagatla 	NULL,
38084400305SSrinivas Kandagatla };
38184400305SSrinivas Kandagatla 
38284400305SSrinivas Kandagatla static const struct attribute_group nvmem_bin_group = {
38384400305SSrinivas Kandagatla 	.bin_attrs	= nvmem_bin_attributes,
38484400305SSrinivas Kandagatla 	.attrs		= nvmem_attrs,
38584400305SSrinivas Kandagatla 	.is_bin_visible = nvmem_bin_attr_is_visible,
3869d7eb234SMarek Vasut 	.is_visible	= nvmem_attr_is_visible,
3870331c611SMiquel Raynal };
3880331c611SMiquel Raynal 
38984400305SSrinivas Kandagatla static const struct attribute_group *nvmem_dev_groups[] = {
39084400305SSrinivas Kandagatla 	&nvmem_bin_group,
39184400305SSrinivas Kandagatla 	NULL,
39284400305SSrinivas Kandagatla };
39384400305SSrinivas Kandagatla 
3942a4542e5SSrinivas Kandagatla static struct bin_attribute bin_attr_nvmem_eeprom_compat = {
39584400305SSrinivas Kandagatla 	.attr	= {
3962a4542e5SSrinivas Kandagatla 		.name	= "eeprom",
39784400305SSrinivas Kandagatla 	},
39884400305SSrinivas Kandagatla 	.read	= bin_attr_nvmem_read,
39984400305SSrinivas Kandagatla 	.write	= bin_attr_nvmem_write,
40084400305SSrinivas Kandagatla };
40184400305SSrinivas Kandagatla 
40284400305SSrinivas Kandagatla /*
40384400305SSrinivas Kandagatla  * nvmem_setup_compat() - Create an additional binary entry in
40484400305SSrinivas Kandagatla  * drivers sys directory, to be backwards compatible with the older
40584400305SSrinivas Kandagatla  * drivers/misc/eeprom drivers.
40684400305SSrinivas Kandagatla  */
nvmem_sysfs_setup_compat(struct nvmem_device * nvmem,const struct nvmem_config * config)40784400305SSrinivas Kandagatla static int nvmem_sysfs_setup_compat(struct nvmem_device *nvmem,
40884400305SSrinivas Kandagatla 				    const struct nvmem_config *config)
40984400305SSrinivas Kandagatla {
41084400305SSrinivas Kandagatla 	int rval;
41184400305SSrinivas Kandagatla 
41284400305SSrinivas Kandagatla 	if (!config->compat)
41384400305SSrinivas Kandagatla 		return 0;
41484400305SSrinivas Kandagatla 
41584400305SSrinivas Kandagatla 	if (!config->base_dev)
41684400305SSrinivas Kandagatla 		return -EINVAL;
41784400305SSrinivas Kandagatla 
4182a4542e5SSrinivas Kandagatla 	nvmem->eeprom = bin_attr_nvmem_eeprom_compat;
4190ba424c9SThomas Weißschuh 	if (config->type == NVMEM_TYPE_FRAM)
4200ba424c9SThomas Weißschuh 		nvmem->eeprom.attr.name = "fram";
4212a4542e5SSrinivas Kandagatla 	nvmem->eeprom.attr.mode = nvmem_bin_attr_get_umode(nvmem);
42284400305SSrinivas Kandagatla 	nvmem->eeprom.size = nvmem->size;
42384400305SSrinivas Kandagatla #ifdef CONFIG_DEBUG_LOCK_ALLOC
42484400305SSrinivas Kandagatla 	nvmem->eeprom.attr.key = &eeprom_lock_key;
42584400305SSrinivas Kandagatla #endif
42684400305SSrinivas Kandagatla 	nvmem->eeprom.private = &nvmem->dev;
42784400305SSrinivas Kandagatla 	nvmem->base_dev = config->base_dev;
42884400305SSrinivas Kandagatla 
42984400305SSrinivas Kandagatla 	rval = device_create_bin_file(nvmem->base_dev, &nvmem->eeprom);
43084400305SSrinivas Kandagatla 	if (rval) {
43184400305SSrinivas Kandagatla 		dev_err(&nvmem->dev,
43284400305SSrinivas Kandagatla 			"Failed to create eeprom binary file %d\n", rval);
43384400305SSrinivas Kandagatla 		return rval;
43484400305SSrinivas Kandagatla 	}
43584400305SSrinivas Kandagatla 
43684400305SSrinivas Kandagatla 	nvmem->flags |= FLAG_COMPAT;
43784400305SSrinivas Kandagatla 
43884400305SSrinivas Kandagatla 	return 0;
43984400305SSrinivas Kandagatla }
44084400305SSrinivas Kandagatla 
nvmem_sysfs_remove_compat(struct nvmem_device * nvmem,const struct nvmem_config * config)44184400305SSrinivas Kandagatla static void nvmem_sysfs_remove_compat(struct nvmem_device *nvmem,
44284400305SSrinivas Kandagatla 			      const struct nvmem_config *config)
44384400305SSrinivas Kandagatla {
44484400305SSrinivas Kandagatla 	if (config->compat)
44584400305SSrinivas Kandagatla 		device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom);
44684400305SSrinivas Kandagatla }
44784400305SSrinivas Kandagatla 
nvmem_populate_sysfs_cells(struct nvmem_device * nvmem)4480331c611SMiquel Raynal static int nvmem_populate_sysfs_cells(struct nvmem_device *nvmem)
4490331c611SMiquel Raynal {
4506839fed0SThomas Weißschuh 	struct attribute_group group = {
4516839fed0SThomas Weißschuh 		.name	= "cells",
4526839fed0SThomas Weißschuh 	};
4530331c611SMiquel Raynal 	struct nvmem_cell_entry *entry;
4546839fed0SThomas Weißschuh 	struct bin_attribute *attrs;
4550331c611SMiquel Raynal 	unsigned int ncells = 0, i = 0;
4560331c611SMiquel Raynal 	int ret = 0;
4570331c611SMiquel Raynal 
4580331c611SMiquel Raynal 	mutex_lock(&nvmem_mutex);
4590331c611SMiquel Raynal 
4606839fed0SThomas Weißschuh 	if (list_empty(&nvmem->cells) || nvmem->sysfs_cells_populated)
4610331c611SMiquel Raynal 		goto unlock_mutex;
4620331c611SMiquel Raynal 
4630331c611SMiquel Raynal 	/* Allocate an array of attributes with a sentinel */
4640331c611SMiquel Raynal 	ncells = list_count_nodes(&nvmem->cells);
4656839fed0SThomas Weißschuh 	group.bin_attrs = devm_kcalloc(&nvmem->dev, ncells + 1,
4660331c611SMiquel Raynal 				       sizeof(struct bin_attribute *), GFP_KERNEL);
4676839fed0SThomas Weißschuh 	if (!group.bin_attrs) {
4680331c611SMiquel Raynal 		ret = -ENOMEM;
4690331c611SMiquel Raynal 		goto unlock_mutex;
4700331c611SMiquel Raynal 	}
4710331c611SMiquel Raynal 
4720331c611SMiquel Raynal 	attrs = devm_kcalloc(&nvmem->dev, ncells, sizeof(struct bin_attribute), GFP_KERNEL);
4730331c611SMiquel Raynal 	if (!attrs) {
4740331c611SMiquel Raynal 		ret = -ENOMEM;
4750331c611SMiquel Raynal 		goto unlock_mutex;
4760331c611SMiquel Raynal 	}
4770331c611SMiquel Raynal 
4780331c611SMiquel Raynal 	/* Initialize each attribute to take the name and size of the cell */
4790331c611SMiquel Raynal 	list_for_each_entry(entry, &nvmem->cells, node) {
4800331c611SMiquel Raynal 		sysfs_bin_attr_init(&attrs[i]);
4810331c611SMiquel Raynal 		attrs[i].attr.name = devm_kasprintf(&nvmem->dev, GFP_KERNEL,
482e20f378dSArnd Bergmann 						    "%s@%x,%x", entry->name,
483e20f378dSArnd Bergmann 						    entry->offset,
484e20f378dSArnd Bergmann 						    entry->bit_offset);
4856bef98baSThomas Weißschuh 		attrs[i].attr.mode = 0444 & nvmem_bin_attr_get_umode(nvmem);
4860331c611SMiquel Raynal 		attrs[i].size = entry->bytes;
4870331c611SMiquel Raynal 		attrs[i].read = &nvmem_cell_attr_read;
4880331c611SMiquel Raynal 		attrs[i].private = entry;
4890331c611SMiquel Raynal 		if (!attrs[i].attr.name) {
4900331c611SMiquel Raynal 			ret = -ENOMEM;
4910331c611SMiquel Raynal 			goto unlock_mutex;
4920331c611SMiquel Raynal 		}
4930331c611SMiquel Raynal 
4946839fed0SThomas Weißschuh 		group.bin_attrs[i] = &attrs[i];
4950331c611SMiquel Raynal 		i++;
4960331c611SMiquel Raynal 	}
4970331c611SMiquel Raynal 
4986839fed0SThomas Weißschuh 	ret = device_add_group(&nvmem->dev, &group);
4990331c611SMiquel Raynal 	if (ret)
5000331c611SMiquel Raynal 		goto unlock_mutex;
5010331c611SMiquel Raynal 
5020331c611SMiquel Raynal 	nvmem->sysfs_cells_populated = true;
5030331c611SMiquel Raynal 
5040331c611SMiquel Raynal unlock_mutex:
5050331c611SMiquel Raynal 	mutex_unlock(&nvmem_mutex);
5060331c611SMiquel Raynal 
5070331c611SMiquel Raynal 	return ret;
5080331c611SMiquel Raynal }
5090331c611SMiquel Raynal 
51084400305SSrinivas Kandagatla #else /* CONFIG_NVMEM_SYSFS */
51184400305SSrinivas Kandagatla 
nvmem_sysfs_setup_compat(struct nvmem_device * nvmem,const struct nvmem_config * config)51284400305SSrinivas Kandagatla static int nvmem_sysfs_setup_compat(struct nvmem_device *nvmem,
51384400305SSrinivas Kandagatla 				    const struct nvmem_config *config)
51484400305SSrinivas Kandagatla {
51584400305SSrinivas Kandagatla 	return -ENOSYS;
51684400305SSrinivas Kandagatla }
nvmem_sysfs_remove_compat(struct nvmem_device * nvmem,const struct nvmem_config * config)51784400305SSrinivas Kandagatla static void nvmem_sysfs_remove_compat(struct nvmem_device *nvmem,
51884400305SSrinivas Kandagatla 				      const struct nvmem_config *config)
51984400305SSrinivas Kandagatla {
52084400305SSrinivas Kandagatla }
52184400305SSrinivas Kandagatla 
52284400305SSrinivas Kandagatla #endif /* CONFIG_NVMEM_SYSFS */
523a8b44d5dSAndy Shevchenko 
nvmem_release(struct device * dev)524eace75cfSSrinivas Kandagatla static void nvmem_release(struct device *dev)
525eace75cfSSrinivas Kandagatla {
526eace75cfSSrinivas Kandagatla 	struct nvmem_device *nvmem = to_nvmem_device(dev);
527eace75cfSSrinivas Kandagatla 
5281eb51d6aSBartosz Golaszewski 	ida_free(&nvmem_ida, nvmem->id);
529a9c3766cSKhouloud Touil 	gpiod_put(nvmem->wp_gpio);
530eace75cfSSrinivas Kandagatla 	kfree(nvmem);
531eace75cfSSrinivas Kandagatla }
532eace75cfSSrinivas Kandagatla 
533eace75cfSSrinivas Kandagatla static const struct device_type nvmem_provider_type = {
534eace75cfSSrinivas Kandagatla 	.release	= nvmem_release,
535eace75cfSSrinivas Kandagatla };
536eace75cfSSrinivas Kandagatla 
537eace75cfSSrinivas Kandagatla static struct bus_type nvmem_bus_type = {
538eace75cfSSrinivas Kandagatla 	.name		= "nvmem",
539eace75cfSSrinivas Kandagatla };
540eace75cfSSrinivas Kandagatla 
nvmem_cell_entry_drop(struct nvmem_cell_entry * cell)5417ae6478bSSrinivas Kandagatla static void nvmem_cell_entry_drop(struct nvmem_cell_entry *cell)
542eace75cfSSrinivas Kandagatla {
543bee1138bSBartosz Golaszewski 	blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_REMOVE, cell);
544c7235ee3SBartosz Golaszewski 	mutex_lock(&nvmem_mutex);
545eace75cfSSrinivas Kandagatla 	list_del(&cell->node);
546c7235ee3SBartosz Golaszewski 	mutex_unlock(&nvmem_mutex);
5470749aa25SSrinivas Kandagatla 	of_node_put(cell->np);
54816bb7abcSBitan Biswas 	kfree_const(cell->name);
549eace75cfSSrinivas Kandagatla 	kfree(cell);
550eace75cfSSrinivas Kandagatla }
551eace75cfSSrinivas Kandagatla 
nvmem_device_remove_all_cells(const struct nvmem_device * nvmem)552eace75cfSSrinivas Kandagatla static void nvmem_device_remove_all_cells(const struct nvmem_device *nvmem)
553eace75cfSSrinivas Kandagatla {
5547ae6478bSSrinivas Kandagatla 	struct nvmem_cell_entry *cell, *p;
555eace75cfSSrinivas Kandagatla 
556c7235ee3SBartosz Golaszewski 	list_for_each_entry_safe(cell, p, &nvmem->cells, node)
5577ae6478bSSrinivas Kandagatla 		nvmem_cell_entry_drop(cell);
558eace75cfSSrinivas Kandagatla }
559eace75cfSSrinivas Kandagatla 
nvmem_cell_entry_add(struct nvmem_cell_entry * cell)5607ae6478bSSrinivas Kandagatla static void nvmem_cell_entry_add(struct nvmem_cell_entry *cell)
561eace75cfSSrinivas Kandagatla {
562c7235ee3SBartosz Golaszewski 	mutex_lock(&nvmem_mutex);
563c7235ee3SBartosz Golaszewski 	list_add_tail(&cell->node, &cell->nvmem->cells);
564c7235ee3SBartosz Golaszewski 	mutex_unlock(&nvmem_mutex);
565bee1138bSBartosz Golaszewski 	blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_ADD, cell);
566eace75cfSSrinivas Kandagatla }
567eace75cfSSrinivas Kandagatla 
nvmem_cell_info_to_nvmem_cell_entry_nodup(struct nvmem_device * nvmem,const struct nvmem_cell_info * info,struct nvmem_cell_entry * cell)5687ae6478bSSrinivas Kandagatla static int nvmem_cell_info_to_nvmem_cell_entry_nodup(struct nvmem_device *nvmem,
569eace75cfSSrinivas Kandagatla 						     const struct nvmem_cell_info *info,
5707ae6478bSSrinivas Kandagatla 						     struct nvmem_cell_entry *cell)
571eace75cfSSrinivas Kandagatla {
572eace75cfSSrinivas Kandagatla 	cell->nvmem = nvmem;
573eace75cfSSrinivas Kandagatla 	cell->offset = info->offset;
57455d4980cSRafał Miłecki 	cell->raw_len = info->raw_len ?: info->bytes;
575eace75cfSSrinivas Kandagatla 	cell->bytes = info->bytes;
576fc9eec4dSVadym Kochan 	cell->name = info->name;
577345ec382SMichael Walle 	cell->read_post_process = info->read_post_process;
5788a134fd9SMichael Walle 	cell->priv = info->priv;
579eace75cfSSrinivas Kandagatla 
580eace75cfSSrinivas Kandagatla 	cell->bit_offset = info->bit_offset;
581eace75cfSSrinivas Kandagatla 	cell->nbits = info->nbits;
582dbc2f620SRafał Miłecki 	cell->np = info->np;
583eace75cfSSrinivas Kandagatla 
584eace75cfSSrinivas Kandagatla 	if (cell->nbits)
585eace75cfSSrinivas Kandagatla 		cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset,
586eace75cfSSrinivas Kandagatla 					   BITS_PER_BYTE);
587eace75cfSSrinivas Kandagatla 
588eace75cfSSrinivas Kandagatla 	if (!IS_ALIGNED(cell->offset, nvmem->stride)) {
589eace75cfSSrinivas Kandagatla 		dev_err(&nvmem->dev,
590eace75cfSSrinivas Kandagatla 			"cell %s unaligned to nvmem stride %d\n",
591fc9eec4dSVadym Kochan 			cell->name ?: "<unknown>", nvmem->stride);
592eace75cfSSrinivas Kandagatla 		return -EINVAL;
593eace75cfSSrinivas Kandagatla 	}
594eace75cfSSrinivas Kandagatla 
595eace75cfSSrinivas Kandagatla 	return 0;
596eace75cfSSrinivas Kandagatla }
597eace75cfSSrinivas Kandagatla 
nvmem_cell_info_to_nvmem_cell_entry(struct nvmem_device * nvmem,const struct nvmem_cell_info * info,struct nvmem_cell_entry * cell)5987ae6478bSSrinivas Kandagatla static int nvmem_cell_info_to_nvmem_cell_entry(struct nvmem_device *nvmem,
599fc9eec4dSVadym Kochan 					       const struct nvmem_cell_info *info,
6007ae6478bSSrinivas Kandagatla 					       struct nvmem_cell_entry *cell)
601fc9eec4dSVadym Kochan {
602fc9eec4dSVadym Kochan 	int err;
603fc9eec4dSVadym Kochan 
6047ae6478bSSrinivas Kandagatla 	err = nvmem_cell_info_to_nvmem_cell_entry_nodup(nvmem, info, cell);
605fc9eec4dSVadym Kochan 	if (err)
606fc9eec4dSVadym Kochan 		return err;
607fc9eec4dSVadym Kochan 
608fc9eec4dSVadym Kochan 	cell->name = kstrdup_const(info->name, GFP_KERNEL);
609fc9eec4dSVadym Kochan 	if (!cell->name)
610fc9eec4dSVadym Kochan 		return -ENOMEM;
611fc9eec4dSVadym Kochan 
612fc9eec4dSVadym Kochan 	return 0;
613fc9eec4dSVadym Kochan }
614fc9eec4dSVadym Kochan 
615b3db17e4SAndrew Lunn /**
6162ded6830SMichael Walle  * nvmem_add_one_cell() - Add one cell information to an nvmem device
6172ded6830SMichael Walle  *
6182ded6830SMichael Walle  * @nvmem: nvmem device to add cells to.
6192ded6830SMichael Walle  * @info: nvmem cell info to add to the device
6202ded6830SMichael Walle  *
6212ded6830SMichael Walle  * Return: 0 or negative error code on failure.
6222ded6830SMichael Walle  */
nvmem_add_one_cell(struct nvmem_device * nvmem,const struct nvmem_cell_info * info)6232ded6830SMichael Walle int nvmem_add_one_cell(struct nvmem_device *nvmem,
6242ded6830SMichael Walle 		       const struct nvmem_cell_info *info)
6252ded6830SMichael Walle {
6262ded6830SMichael Walle 	struct nvmem_cell_entry *cell;
6272ded6830SMichael Walle 	int rval;
6282ded6830SMichael Walle 
6292ded6830SMichael Walle 	cell = kzalloc(sizeof(*cell), GFP_KERNEL);
6302ded6830SMichael Walle 	if (!cell)
6312ded6830SMichael Walle 		return -ENOMEM;
6322ded6830SMichael Walle 
6332ded6830SMichael Walle 	rval = nvmem_cell_info_to_nvmem_cell_entry(nvmem, info, cell);
6342ded6830SMichael Walle 	if (rval) {
6352ded6830SMichael Walle 		kfree(cell);
6362ded6830SMichael Walle 		return rval;
6372ded6830SMichael Walle 	}
6382ded6830SMichael Walle 
6392ded6830SMichael Walle 	nvmem_cell_entry_add(cell);
6402ded6830SMichael Walle 
6412ded6830SMichael Walle 	return 0;
6422ded6830SMichael Walle }
6432ded6830SMichael Walle EXPORT_SYMBOL_GPL(nvmem_add_one_cell);
6442ded6830SMichael Walle 
6452ded6830SMichael Walle /**
646b3db17e4SAndrew Lunn  * nvmem_add_cells() - Add cell information to an nvmem device
647b3db17e4SAndrew Lunn  *
648b3db17e4SAndrew Lunn  * @nvmem: nvmem device to add cells to.
649b3db17e4SAndrew Lunn  * @info: nvmem cell info to add to the device
650b3db17e4SAndrew Lunn  * @ncells: number of cells in info
651b3db17e4SAndrew Lunn  *
652b3db17e4SAndrew Lunn  * Return: 0 or negative error code on failure.
653b3db17e4SAndrew Lunn  */
nvmem_add_cells(struct nvmem_device * nvmem,const struct nvmem_cell_info * info,int ncells)654ef92ab30SSrinivas Kandagatla static int nvmem_add_cells(struct nvmem_device *nvmem,
655b3db17e4SAndrew Lunn 		    const struct nvmem_cell_info *info,
656b3db17e4SAndrew Lunn 		    int ncells)
657eace75cfSSrinivas Kandagatla {
6582ded6830SMichael Walle 	int i, rval;
659eace75cfSSrinivas Kandagatla 
660b3db17e4SAndrew Lunn 	for (i = 0; i < ncells; i++) {
6612ded6830SMichael Walle 		rval = nvmem_add_one_cell(nvmem, &info[i]);
6622ded6830SMichael Walle 		if (rval)
663eace75cfSSrinivas Kandagatla 			return rval;
664eace75cfSSrinivas Kandagatla 	}
665eace75cfSSrinivas Kandagatla 
6662ded6830SMichael Walle 	return 0;
6672ded6830SMichael Walle }
6682ded6830SMichael Walle 
669bee1138bSBartosz Golaszewski /**
670bee1138bSBartosz Golaszewski  * nvmem_register_notifier() - Register a notifier block for nvmem events.
671bee1138bSBartosz Golaszewski  *
672bee1138bSBartosz Golaszewski  * @nb: notifier block to be called on nvmem events.
673bee1138bSBartosz Golaszewski  *
674bee1138bSBartosz Golaszewski  * Return: 0 on success, negative error number on failure.
675bee1138bSBartosz Golaszewski  */
nvmem_register_notifier(struct notifier_block * nb)676bee1138bSBartosz Golaszewski int nvmem_register_notifier(struct notifier_block *nb)
677bee1138bSBartosz Golaszewski {
678bee1138bSBartosz Golaszewski 	return blocking_notifier_chain_register(&nvmem_notifier, nb);
679bee1138bSBartosz Golaszewski }
680bee1138bSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_register_notifier);
681bee1138bSBartosz Golaszewski 
682bee1138bSBartosz Golaszewski /**
683bee1138bSBartosz Golaszewski  * nvmem_unregister_notifier() - Unregister a notifier block for nvmem events.
684bee1138bSBartosz Golaszewski  *
685bee1138bSBartosz Golaszewski  * @nb: notifier block to be unregistered.
686bee1138bSBartosz Golaszewski  *
687bee1138bSBartosz Golaszewski  * Return: 0 on success, negative error number on failure.
688bee1138bSBartosz Golaszewski  */
nvmem_unregister_notifier(struct notifier_block * nb)689bee1138bSBartosz Golaszewski int nvmem_unregister_notifier(struct notifier_block *nb)
690bee1138bSBartosz Golaszewski {
691bee1138bSBartosz Golaszewski 	return blocking_notifier_chain_unregister(&nvmem_notifier, nb);
692bee1138bSBartosz Golaszewski }
693bee1138bSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_unregister_notifier);
694bee1138bSBartosz Golaszewski 
nvmem_add_cells_from_table(struct nvmem_device * nvmem)695b985f4cbSBartosz Golaszewski static int nvmem_add_cells_from_table(struct nvmem_device *nvmem)
696b985f4cbSBartosz Golaszewski {
697b985f4cbSBartosz Golaszewski 	const struct nvmem_cell_info *info;
698b985f4cbSBartosz Golaszewski 	struct nvmem_cell_table *table;
6997ae6478bSSrinivas Kandagatla 	struct nvmem_cell_entry *cell;
700b985f4cbSBartosz Golaszewski 	int rval = 0, i;
701b985f4cbSBartosz Golaszewski 
702b985f4cbSBartosz Golaszewski 	mutex_lock(&nvmem_cell_mutex);
703b985f4cbSBartosz Golaszewski 	list_for_each_entry(table, &nvmem_cell_tables, node) {
704b985f4cbSBartosz Golaszewski 		if (strcmp(nvmem_dev_name(nvmem), table->nvmem_name) == 0) {
705b985f4cbSBartosz Golaszewski 			for (i = 0; i < table->ncells; i++) {
706b985f4cbSBartosz Golaszewski 				info = &table->cells[i];
707b985f4cbSBartosz Golaszewski 
708b985f4cbSBartosz Golaszewski 				cell = kzalloc(sizeof(*cell), GFP_KERNEL);
709b985f4cbSBartosz Golaszewski 				if (!cell) {
710b985f4cbSBartosz Golaszewski 					rval = -ENOMEM;
711b985f4cbSBartosz Golaszewski 					goto out;
712b985f4cbSBartosz Golaszewski 				}
713b985f4cbSBartosz Golaszewski 
7147ae6478bSSrinivas Kandagatla 				rval = nvmem_cell_info_to_nvmem_cell_entry(nvmem, info, cell);
715b985f4cbSBartosz Golaszewski 				if (rval) {
716b985f4cbSBartosz Golaszewski 					kfree(cell);
717b985f4cbSBartosz Golaszewski 					goto out;
718b985f4cbSBartosz Golaszewski 				}
719b985f4cbSBartosz Golaszewski 
7207ae6478bSSrinivas Kandagatla 				nvmem_cell_entry_add(cell);
721b985f4cbSBartosz Golaszewski 			}
722b985f4cbSBartosz Golaszewski 		}
723b985f4cbSBartosz Golaszewski 	}
724b985f4cbSBartosz Golaszewski 
725b985f4cbSBartosz Golaszewski out:
726b985f4cbSBartosz Golaszewski 	mutex_unlock(&nvmem_cell_mutex);
727b985f4cbSBartosz Golaszewski 	return rval;
728b985f4cbSBartosz Golaszewski }
729b985f4cbSBartosz Golaszewski 
7307ae6478bSSrinivas Kandagatla static struct nvmem_cell_entry *
nvmem_find_cell_entry_by_name(struct nvmem_device * nvmem,const char * cell_id)7317ae6478bSSrinivas Kandagatla nvmem_find_cell_entry_by_name(struct nvmem_device *nvmem, const char *cell_id)
732506157beSBartosz Golaszewski {
7337ae6478bSSrinivas Kandagatla 	struct nvmem_cell_entry *iter, *cell = NULL;
734506157beSBartosz Golaszewski 
735506157beSBartosz Golaszewski 	mutex_lock(&nvmem_mutex);
7361c832674SAlban Bedel 	list_for_each_entry(iter, &nvmem->cells, node) {
7371c832674SAlban Bedel 		if (strcmp(cell_id, iter->name) == 0) {
7381c832674SAlban Bedel 			cell = iter;
739506157beSBartosz Golaszewski 			break;
740506157beSBartosz Golaszewski 		}
7411c832674SAlban Bedel 	}
742506157beSBartosz Golaszewski 	mutex_unlock(&nvmem_mutex);
743506157beSBartosz Golaszewski 
744506157beSBartosz Golaszewski 	return cell;
745506157beSBartosz Golaszewski }
746506157beSBartosz Golaszewski 
nvmem_validate_keepouts(struct nvmem_device * nvmem)747fd3bb8f5SEvan Green static int nvmem_validate_keepouts(struct nvmem_device *nvmem)
748fd3bb8f5SEvan Green {
749fd3bb8f5SEvan Green 	unsigned int cur = 0;
750fd3bb8f5SEvan Green 	const struct nvmem_keepout *keepout = nvmem->keepout;
751fd3bb8f5SEvan Green 	const struct nvmem_keepout *keepoutend = keepout + nvmem->nkeepout;
752fd3bb8f5SEvan Green 
753fd3bb8f5SEvan Green 	while (keepout < keepoutend) {
754fd3bb8f5SEvan Green 		/* Ensure keepouts are sorted and don't overlap. */
755fd3bb8f5SEvan Green 		if (keepout->start < cur) {
756fd3bb8f5SEvan Green 			dev_err(&nvmem->dev,
757fd3bb8f5SEvan Green 				"Keepout regions aren't sorted or overlap.\n");
758fd3bb8f5SEvan Green 
759fd3bb8f5SEvan Green 			return -ERANGE;
760fd3bb8f5SEvan Green 		}
761fd3bb8f5SEvan Green 
762fd3bb8f5SEvan Green 		if (keepout->end < keepout->start) {
763fd3bb8f5SEvan Green 			dev_err(&nvmem->dev,
764fd3bb8f5SEvan Green 				"Invalid keepout region.\n");
765fd3bb8f5SEvan Green 
766fd3bb8f5SEvan Green 			return -EINVAL;
767fd3bb8f5SEvan Green 		}
768fd3bb8f5SEvan Green 
769fd3bb8f5SEvan Green 		/*
770fd3bb8f5SEvan Green 		 * Validate keepouts (and holes between) don't violate
771fd3bb8f5SEvan Green 		 * word_size constraints.
772fd3bb8f5SEvan Green 		 */
773fd3bb8f5SEvan Green 		if ((keepout->end - keepout->start < nvmem->word_size) ||
774fd3bb8f5SEvan Green 		    ((keepout->start != cur) &&
775fd3bb8f5SEvan Green 		     (keepout->start - cur < nvmem->word_size))) {
776fd3bb8f5SEvan Green 
777fd3bb8f5SEvan Green 			dev_err(&nvmem->dev,
778fd3bb8f5SEvan Green 				"Keepout regions violate word_size constraints.\n");
779fd3bb8f5SEvan Green 
780fd3bb8f5SEvan Green 			return -ERANGE;
781fd3bb8f5SEvan Green 		}
782fd3bb8f5SEvan Green 
783fd3bb8f5SEvan Green 		/* Validate keepouts don't violate stride (alignment). */
784fd3bb8f5SEvan Green 		if (!IS_ALIGNED(keepout->start, nvmem->stride) ||
785fd3bb8f5SEvan Green 		    !IS_ALIGNED(keepout->end, nvmem->stride)) {
786fd3bb8f5SEvan Green 
787fd3bb8f5SEvan Green 			dev_err(&nvmem->dev,
788fd3bb8f5SEvan Green 				"Keepout regions violate stride.\n");
789fd3bb8f5SEvan Green 
790fd3bb8f5SEvan Green 			return -EINVAL;
791fd3bb8f5SEvan Green 		}
792fd3bb8f5SEvan Green 
793fd3bb8f5SEvan Green 		cur = keepout->end;
794fd3bb8f5SEvan Green 		keepout++;
795fd3bb8f5SEvan Green 	}
796fd3bb8f5SEvan Green 
797fd3bb8f5SEvan Green 	return 0;
798fd3bb8f5SEvan Green }
799fd3bb8f5SEvan Green 
nvmem_add_cells_from_dt(struct nvmem_device * nvmem,struct device_node * np)80027f699e5SRafał Miłecki static int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_node *np)
801e888d445SBartosz Golaszewski {
802e888d445SBartosz Golaszewski 	struct device *dev = &nvmem->dev;
80350014d65SMichael Walle 	struct device_node *child;
804e888d445SBartosz Golaszewski 	const __be32 *addr;
80550014d65SMichael Walle 	int len, ret;
806e888d445SBartosz Golaszewski 
80727f699e5SRafał Miłecki 	for_each_child_of_node(np, child) {
80850014d65SMichael Walle 		struct nvmem_cell_info info = {0};
809e888d445SBartosz Golaszewski 
810e888d445SBartosz Golaszewski 		addr = of_get_property(child, "reg", &len);
8110445efacSAhmad Fatoum 		if (!addr)
8120445efacSAhmad Fatoum 			continue;
8130445efacSAhmad Fatoum 		if (len < 2 * sizeof(u32)) {
814e888d445SBartosz Golaszewski 			dev_err(dev, "nvmem: invalid reg on %pOF\n", child);
81563879e29SChristophe JAILLET 			of_node_put(child);
816e888d445SBartosz Golaszewski 			return -EINVAL;
817e888d445SBartosz Golaszewski 		}
818e888d445SBartosz Golaszewski 
81950014d65SMichael Walle 		info.offset = be32_to_cpup(addr++);
82050014d65SMichael Walle 		info.bytes = be32_to_cpup(addr);
82150014d65SMichael Walle 		info.name = kasprintf(GFP_KERNEL, "%pOFn", child);
822e888d445SBartosz Golaszewski 
823e888d445SBartosz Golaszewski 		addr = of_get_property(child, "bits", &len);
824e888d445SBartosz Golaszewski 		if (addr && len == (2 * sizeof(u32))) {
82550014d65SMichael Walle 			info.bit_offset = be32_to_cpup(addr++);
82650014d65SMichael Walle 			info.nbits = be32_to_cpup(addr);
827def3173dSMarkus Schneider-Pargmann 			if (info.bit_offset >= BITS_PER_BYTE || info.nbits < 1) {
828def3173dSMarkus Schneider-Pargmann 				dev_err(dev, "nvmem: invalid bits on %pOF\n", child);
829def3173dSMarkus Schneider-Pargmann 				of_node_put(child);
830def3173dSMarkus Schneider-Pargmann 				return -EINVAL;
831def3173dSMarkus Schneider-Pargmann 			}
832e888d445SBartosz Golaszewski 		}
833e888d445SBartosz Golaszewski 
83450014d65SMichael Walle 		info.np = of_node_get(child);
835e888d445SBartosz Golaszewski 
8361172460eSMiquel Raynal 		if (nvmem->fixup_dt_cell_info)
8371172460eSMiquel Raynal 			nvmem->fixup_dt_cell_info(nvmem, &info);
838de12c969SMichael Walle 
83950014d65SMichael Walle 		ret = nvmem_add_one_cell(nvmem, &info);
84050014d65SMichael Walle 		kfree(info.name);
84150014d65SMichael Walle 		if (ret) {
84263879e29SChristophe JAILLET 			of_node_put(child);
84350014d65SMichael Walle 			return ret;
844e888d445SBartosz Golaszewski 		}
845e888d445SBartosz Golaszewski 	}
846e888d445SBartosz Golaszewski 
847e888d445SBartosz Golaszewski 	return 0;
848e888d445SBartosz Golaszewski }
849e888d445SBartosz Golaszewski 
nvmem_add_cells_from_legacy_of(struct nvmem_device * nvmem)85027f699e5SRafał Miłecki static int nvmem_add_cells_from_legacy_of(struct nvmem_device *nvmem)
85127f699e5SRafał Miłecki {
85227f699e5SRafał Miłecki 	return nvmem_add_cells_from_dt(nvmem, nvmem->dev.of_node);
85327f699e5SRafał Miłecki }
85427f699e5SRafał Miłecki 
nvmem_add_cells_from_fixed_layout(struct nvmem_device * nvmem)85527f699e5SRafał Miłecki static int nvmem_add_cells_from_fixed_layout(struct nvmem_device *nvmem)
85627f699e5SRafał Miłecki {
85727f699e5SRafał Miłecki 	struct device_node *layout_np;
85827f699e5SRafał Miłecki 	int err = 0;
85927f699e5SRafał Miłecki 
86027f699e5SRafał Miłecki 	layout_np = of_nvmem_layout_get_container(nvmem);
86127f699e5SRafał Miłecki 	if (!layout_np)
86227f699e5SRafał Miłecki 		return 0;
86327f699e5SRafał Miłecki 
86427f699e5SRafał Miłecki 	if (of_device_is_compatible(layout_np, "fixed-layout"))
86527f699e5SRafał Miłecki 		err = nvmem_add_cells_from_dt(nvmem, layout_np);
86627f699e5SRafał Miłecki 
86727f699e5SRafał Miłecki 	of_node_put(layout_np);
86827f699e5SRafał Miłecki 
86927f699e5SRafał Miłecki 	return err;
87027f699e5SRafał Miłecki }
87127f699e5SRafał Miłecki 
nvmem_layout_register(struct nvmem_layout * layout)872fc29fd82SMiquel Raynal int nvmem_layout_register(struct nvmem_layout *layout)
873266570f4SMichael Walle {
8740331c611SMiquel Raynal 	int ret;
8750331c611SMiquel Raynal 
876fc29fd82SMiquel Raynal 	if (!layout->add_cells)
877fc29fd82SMiquel Raynal 		return -EINVAL;
878266570f4SMichael Walle 
879fc29fd82SMiquel Raynal 	/* Populate the cells */
880401df0d4SRafał Miłecki 	ret = layout->add_cells(layout);
8810331c611SMiquel Raynal 	if (ret)
8820331c611SMiquel Raynal 		return ret;
8830331c611SMiquel Raynal 
8840331c611SMiquel Raynal #ifdef CONFIG_NVMEM_SYSFS
8850331c611SMiquel Raynal 	ret = nvmem_populate_sysfs_cells(layout->nvmem);
8860331c611SMiquel Raynal 	if (ret) {
8870331c611SMiquel Raynal 		nvmem_device_remove_all_cells(layout->nvmem);
8880331c611SMiquel Raynal 		return ret;
8890331c611SMiquel Raynal 	}
8900331c611SMiquel Raynal #endif
8910331c611SMiquel Raynal 
8920331c611SMiquel Raynal 	return 0;
893266570f4SMichael Walle }
894fc29fd82SMiquel Raynal EXPORT_SYMBOL_GPL(nvmem_layout_register);
895266570f4SMichael Walle 
nvmem_layout_unregister(struct nvmem_layout * layout)896266570f4SMichael Walle void nvmem_layout_unregister(struct nvmem_layout *layout)
897266570f4SMichael Walle {
898fc29fd82SMiquel Raynal 	/* Keep the API even with an empty stub in case we need it later */
899266570f4SMichael Walle }
900266570f4SMichael Walle EXPORT_SYMBOL_GPL(nvmem_layout_unregister);
901266570f4SMichael Walle 
902eace75cfSSrinivas Kandagatla /**
903eace75cfSSrinivas Kandagatla  * nvmem_register() - Register a nvmem device for given nvmem_config.
9043a758071SAndreas Färber  * Also creates a binary entry in /sys/bus/nvmem/devices/dev-name/nvmem
905eace75cfSSrinivas Kandagatla  *
906eace75cfSSrinivas Kandagatla  * @config: nvmem device configuration with which nvmem device is created.
907eace75cfSSrinivas Kandagatla  *
908eace75cfSSrinivas Kandagatla  * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device
909eace75cfSSrinivas Kandagatla  * on success.
910eace75cfSSrinivas Kandagatla  */
911eace75cfSSrinivas Kandagatla 
nvmem_register(const struct nvmem_config * config)912eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem_register(const struct nvmem_config *config)
913eace75cfSSrinivas Kandagatla {
914eace75cfSSrinivas Kandagatla 	struct nvmem_device *nvmem;
915eace75cfSSrinivas Kandagatla 	int rval;
916eace75cfSSrinivas Kandagatla 
917eace75cfSSrinivas Kandagatla 	if (!config->dev)
918eace75cfSSrinivas Kandagatla 		return ERR_PTR(-EINVAL);
919eace75cfSSrinivas Kandagatla 
920061a320bSSrinivas Kandagatla 	if (!config->reg_read && !config->reg_write)
921061a320bSSrinivas Kandagatla 		return ERR_PTR(-EINVAL);
922061a320bSSrinivas Kandagatla 
923eace75cfSSrinivas Kandagatla 	nvmem = kzalloc(sizeof(*nvmem), GFP_KERNEL);
924eace75cfSSrinivas Kandagatla 	if (!nvmem)
925eace75cfSSrinivas Kandagatla 		return ERR_PTR(-ENOMEM);
926eace75cfSSrinivas Kandagatla 
9271eb51d6aSBartosz Golaszewski 	rval = ida_alloc(&nvmem_ida, GFP_KERNEL);
928eace75cfSSrinivas Kandagatla 	if (rval < 0) {
929eace75cfSSrinivas Kandagatla 		kfree(nvmem);
930eace75cfSSrinivas Kandagatla 		return ERR_PTR(rval);
931eace75cfSSrinivas Kandagatla 	}
93231c6ff51SBartosz Golaszewski 
9333bd747c7SRussell King (Oracle) 	nvmem->id = rval;
9343bd747c7SRussell King (Oracle) 
935560181d3SRussell King (Oracle) 	nvmem->dev.type = &nvmem_provider_type;
936560181d3SRussell King (Oracle) 	nvmem->dev.bus = &nvmem_bus_type;
937560181d3SRussell King (Oracle) 	nvmem->dev.parent = config->dev;
938560181d3SRussell King (Oracle) 
939560181d3SRussell King (Oracle) 	device_initialize(&nvmem->dev);
940560181d3SRussell King (Oracle) 
941569653f0SRussell King (Oracle) 	if (!config->ignore_wp)
9422a127da4SKhouloud Touil 		nvmem->wp_gpio = gpiod_get_optional(config->dev, "wp",
9432a127da4SKhouloud Touil 						    GPIOD_OUT_HIGH);
944f7d8d7dcSBartosz Golaszewski 	if (IS_ERR(nvmem->wp_gpio)) {
945f7d8d7dcSBartosz Golaszewski 		rval = PTR_ERR(nvmem->wp_gpio);
9460c4862b1SRussell King (Oracle) 		nvmem->wp_gpio = NULL;
947560181d3SRussell King (Oracle) 		goto err_put_device;
948f7d8d7dcSBartosz Golaszewski 	}
9492a127da4SKhouloud Touil 
950c1de7f43SBartosz Golaszewski 	kref_init(&nvmem->refcnt);
951c7235ee3SBartosz Golaszewski 	INIT_LIST_HEAD(&nvmem->cells);
9521172460eSMiquel Raynal 	nvmem->fixup_dt_cell_info = config->fixup_dt_cell_info;
953c1de7f43SBartosz Golaszewski 
954eace75cfSSrinivas Kandagatla 	nvmem->owner = config->owner;
95517eb18d6SMasahiro Yamada 	if (!nvmem->owner && config->dev->driver)
95617eb18d6SMasahiro Yamada 		nvmem->owner = config->dev->driver->owner;
95799897efdSHeiner Kallweit 	nvmem->stride = config->stride ?: 1;
95899897efdSHeiner Kallweit 	nvmem->word_size = config->word_size ?: 1;
959795ddd18SSrinivas Kandagatla 	nvmem->size = config->size;
960e6de179dSSrinivas Kandagatla 	nvmem->root_only = config->root_only;
961795ddd18SSrinivas Kandagatla 	nvmem->priv = config->priv;
96216688453SAlexandre Belloni 	nvmem->type = config->type;
963795ddd18SSrinivas Kandagatla 	nvmem->reg_read = config->reg_read;
964795ddd18SSrinivas Kandagatla 	nvmem->reg_write = config->reg_write;
965fd3bb8f5SEvan Green 	nvmem->keepout = config->keepout;
966fd3bb8f5SEvan Green 	nvmem->nkeepout = config->nkeepout;
9671333a677SMichael Walle 	if (config->of_node)
9681333a677SMichael Walle 		nvmem->dev.of_node = config->of_node;
969f4cf4e5dSRafał Miłecki 	else
970fc2f9970SHeiner Kallweit 		nvmem->dev.of_node = config->dev->of_node;
971fd0f4906SAndrey Smirnov 
972731aa3faSSrinivas Kandagatla 	switch (config->id) {
973731aa3faSSrinivas Kandagatla 	case NVMEM_DEVID_NONE:
9745544e90cSGaosheng Cui 		rval = dev_set_name(&nvmem->dev, "%s", config->name);
975731aa3faSSrinivas Kandagatla 		break;
976731aa3faSSrinivas Kandagatla 	case NVMEM_DEVID_AUTO:
9775544e90cSGaosheng Cui 		rval = dev_set_name(&nvmem->dev, "%s%d", config->name, nvmem->id);
978731aa3faSSrinivas Kandagatla 		break;
979731aa3faSSrinivas Kandagatla 	default:
9805544e90cSGaosheng Cui 		rval = dev_set_name(&nvmem->dev, "%s%d",
9815253193dSAban Bedel 			     config->name ? : "nvmem",
9825253193dSAban Bedel 			     config->name ? config->id : nvmem->id);
983731aa3faSSrinivas Kandagatla 		break;
984fd0f4906SAndrey Smirnov 	}
985eace75cfSSrinivas Kandagatla 
986560181d3SRussell King (Oracle) 	if (rval)
987560181d3SRussell King (Oracle) 		goto err_put_device;
9885544e90cSGaosheng Cui 
9891716cfe8SAlban Bedel 	nvmem->read_only = device_property_present(config->dev, "read-only") ||
9901716cfe8SAlban Bedel 			   config->read_only || !nvmem->reg_write;
991eace75cfSSrinivas Kandagatla 
99284400305SSrinivas Kandagatla #ifdef CONFIG_NVMEM_SYSFS
99384400305SSrinivas Kandagatla 	nvmem->dev.groups = nvmem_dev_groups;
99484400305SSrinivas Kandagatla #endif
995eace75cfSSrinivas Kandagatla 
996bd124456SGaosheng Cui 	if (nvmem->nkeepout) {
997bd124456SGaosheng Cui 		rval = nvmem_validate_keepouts(nvmem);
998bd124456SGaosheng Cui 		if (rval)
999ab3428cfSRussell King (Oracle) 			goto err_put_device;
1000bd124456SGaosheng Cui 	}
1001bd124456SGaosheng Cui 
1002b6c217abSAndrew Lunn 	if (config->compat) {
1003ae0c2d72SSrinivas Kandagatla 		rval = nvmem_sysfs_setup_compat(nvmem, config);
1004b6c217abSAndrew Lunn 		if (rval)
1005ab3428cfSRussell King (Oracle) 			goto err_put_device;
1006eace75cfSSrinivas Kandagatla 	}
1007eace75cfSSrinivas Kandagatla 
1008fa72d847SBartosz Golaszewski 	if (config->cells) {
1009fa72d847SBartosz Golaszewski 		rval = nvmem_add_cells(nvmem, config->cells, config->ncells);
1010fa72d847SBartosz Golaszewski 		if (rval)
1011db3546d5SMichael Walle 			goto err_remove_cells;
1012fa72d847SBartosz Golaszewski 	}
1013eace75cfSSrinivas Kandagatla 
1014b985f4cbSBartosz Golaszewski 	rval = nvmem_add_cells_from_table(nvmem);
1015b985f4cbSBartosz Golaszewski 	if (rval)
1016b985f4cbSBartosz Golaszewski 		goto err_remove_cells;
1017b985f4cbSBartosz Golaszewski 
10182cc3b37fSRafał Miłecki 	if (config->add_legacy_fixed_of_cells) {
101927f699e5SRafał Miłecki 		rval = nvmem_add_cells_from_legacy_of(nvmem);
1020e888d445SBartosz Golaszewski 		if (rval)
1021e888d445SBartosz Golaszewski 			goto err_remove_cells;
10222cc3b37fSRafał Miłecki 	}
1023e888d445SBartosz Golaszewski 
102427f699e5SRafał Miłecki 	rval = nvmem_add_cells_from_fixed_layout(nvmem);
102527f699e5SRafał Miłecki 	if (rval)
102627f699e5SRafał Miłecki 		goto err_remove_cells;
102727f699e5SRafał Miłecki 
1028f4d1d17eSMiquel Raynal 	dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name);
1029f4d1d17eSMiquel Raynal 
1030f4d1d17eSMiquel Raynal 	rval = device_add(&nvmem->dev);
1031f4d1d17eSMiquel Raynal 	if (rval)
1032f4d1d17eSMiquel Raynal 		goto err_remove_cells;
1033f4d1d17eSMiquel Raynal 
1034fc29fd82SMiquel Raynal 	rval = nvmem_populate_layout(nvmem);
1035fc29fd82SMiquel Raynal 	if (rval)
1036fc29fd82SMiquel Raynal 		goto err_remove_dev;
1037fc29fd82SMiquel Raynal 
10380331c611SMiquel Raynal #ifdef CONFIG_NVMEM_SYSFS
10390331c611SMiquel Raynal 	rval = nvmem_populate_sysfs_cells(nvmem);
10400331c611SMiquel Raynal 	if (rval)
10410331c611SMiquel Raynal 		goto err_destroy_layout;
10420331c611SMiquel Raynal #endif
10430331c611SMiquel Raynal 
1044f4853e1cSBartosz Golaszewski 	blocking_notifier_call_chain(&nvmem_notifier, NVMEM_ADD, nvmem);
1045bee1138bSBartosz Golaszewski 
1046eace75cfSSrinivas Kandagatla 	return nvmem;
10473360acdfSJohan Hovold 
10480331c611SMiquel Raynal #ifdef CONFIG_NVMEM_SYSFS
10490331c611SMiquel Raynal err_destroy_layout:
10500331c611SMiquel Raynal 	nvmem_destroy_layout(nvmem);
10510331c611SMiquel Raynal #endif
1052fc29fd82SMiquel Raynal err_remove_dev:
1053fc29fd82SMiquel Raynal 	device_del(&nvmem->dev);
1054b985f4cbSBartosz Golaszewski err_remove_cells:
1055b985f4cbSBartosz Golaszewski 	nvmem_device_remove_all_cells(nvmem);
1056fa72d847SBartosz Golaszewski 	if (config->compat)
1057ae0c2d72SSrinivas Kandagatla 		nvmem_sysfs_remove_compat(nvmem, config);
10583360acdfSJohan Hovold err_put_device:
10593360acdfSJohan Hovold 	put_device(&nvmem->dev);
10603360acdfSJohan Hovold 
1061b6c217abSAndrew Lunn 	return ERR_PTR(rval);
1062eace75cfSSrinivas Kandagatla }
1063eace75cfSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_register);
1064eace75cfSSrinivas Kandagatla 
nvmem_device_release(struct kref * kref)1065c1de7f43SBartosz Golaszewski static void nvmem_device_release(struct kref *kref)
1066c1de7f43SBartosz Golaszewski {
1067c1de7f43SBartosz Golaszewski 	struct nvmem_device *nvmem;
1068c1de7f43SBartosz Golaszewski 
1069c1de7f43SBartosz Golaszewski 	nvmem = container_of(kref, struct nvmem_device, refcnt);
1070c1de7f43SBartosz Golaszewski 
1071bee1138bSBartosz Golaszewski 	blocking_notifier_call_chain(&nvmem_notifier, NVMEM_REMOVE, nvmem);
1072bee1138bSBartosz Golaszewski 
1073c1de7f43SBartosz Golaszewski 	if (nvmem->flags & FLAG_COMPAT)
1074c1de7f43SBartosz Golaszewski 		device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom);
1075c1de7f43SBartosz Golaszewski 
1076c1de7f43SBartosz Golaszewski 	nvmem_device_remove_all_cells(nvmem);
1077fc29fd82SMiquel Raynal 	nvmem_destroy_layout(nvmem);
1078f60442ddSSrinivas Kandagatla 	device_unregister(&nvmem->dev);
1079c1de7f43SBartosz Golaszewski }
1080c1de7f43SBartosz Golaszewski 
1081eace75cfSSrinivas Kandagatla /**
1082eace75cfSSrinivas Kandagatla  * nvmem_unregister() - Unregister previously registered nvmem device
1083eace75cfSSrinivas Kandagatla  *
1084eace75cfSSrinivas Kandagatla  * @nvmem: Pointer to previously registered nvmem device.
1085eace75cfSSrinivas Kandagatla  */
nvmem_unregister(struct nvmem_device * nvmem)1086bf58e882SBartosz Golaszewski void nvmem_unregister(struct nvmem_device *nvmem)
1087eace75cfSSrinivas Kandagatla {
10888c751e0dSAndy Shevchenko 	if (nvmem)
1089c1de7f43SBartosz Golaszewski 		kref_put(&nvmem->refcnt, nvmem_device_release);
1090eace75cfSSrinivas Kandagatla }
1091eace75cfSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_unregister);
1092eace75cfSSrinivas Kandagatla 
devm_nvmem_unregister(void * nvmem)10935825b2c6SAndy Shevchenko static void devm_nvmem_unregister(void *nvmem)
1094f1f50ecaSAndrey Smirnov {
10955825b2c6SAndy Shevchenko 	nvmem_unregister(nvmem);
1096f1f50ecaSAndrey Smirnov }
1097f1f50ecaSAndrey Smirnov 
1098f1f50ecaSAndrey Smirnov /**
1099f1f50ecaSAndrey Smirnov  * devm_nvmem_register() - Register a managed nvmem device for given
1100f1f50ecaSAndrey Smirnov  * nvmem_config.
11013a758071SAndreas Färber  * Also creates a binary entry in /sys/bus/nvmem/devices/dev-name/nvmem
1102f1f50ecaSAndrey Smirnov  *
1103b378c779SSrinivas Kandagatla  * @dev: Device that uses the nvmem device.
1104f1f50ecaSAndrey Smirnov  * @config: nvmem device configuration with which nvmem device is created.
1105f1f50ecaSAndrey Smirnov  *
1106f1f50ecaSAndrey Smirnov  * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device
1107f1f50ecaSAndrey Smirnov  * on success.
1108f1f50ecaSAndrey Smirnov  */
devm_nvmem_register(struct device * dev,const struct nvmem_config * config)1109f1f50ecaSAndrey Smirnov struct nvmem_device *devm_nvmem_register(struct device *dev,
1110f1f50ecaSAndrey Smirnov 					 const struct nvmem_config *config)
1111f1f50ecaSAndrey Smirnov {
11125825b2c6SAndy Shevchenko 	struct nvmem_device *nvmem;
11135825b2c6SAndy Shevchenko 	int ret;
1114f1f50ecaSAndrey Smirnov 
1115f1f50ecaSAndrey Smirnov 	nvmem = nvmem_register(config);
11165825b2c6SAndy Shevchenko 	if (IS_ERR(nvmem))
11175825b2c6SAndy Shevchenko 		return nvmem;
1118f1f50ecaSAndrey Smirnov 
11195825b2c6SAndy Shevchenko 	ret = devm_add_action_or_reset(dev, devm_nvmem_unregister, nvmem);
11205825b2c6SAndy Shevchenko 	if (ret)
11215825b2c6SAndy Shevchenko 		return ERR_PTR(ret);
1122f1f50ecaSAndrey Smirnov 
1123f1f50ecaSAndrey Smirnov 	return nvmem;
1124f1f50ecaSAndrey Smirnov }
1125f1f50ecaSAndrey Smirnov EXPORT_SYMBOL_GPL(devm_nvmem_register);
1126f1f50ecaSAndrey Smirnov 
__nvmem_device_get(void * data,int (* match)(struct device * dev,const void * data))11278c2a2b8cSThomas Bogendoerfer static struct nvmem_device *__nvmem_device_get(void *data,
11288c2a2b8cSThomas Bogendoerfer 			int (*match)(struct device *dev, const void *data))
112969aba794SSrinivas Kandagatla {
113069aba794SSrinivas Kandagatla 	struct nvmem_device *nvmem = NULL;
11318c2a2b8cSThomas Bogendoerfer 	struct device *dev;
113269aba794SSrinivas Kandagatla 
1133c7235ee3SBartosz Golaszewski 	mutex_lock(&nvmem_mutex);
11348c2a2b8cSThomas Bogendoerfer 	dev = bus_find_device(&nvmem_bus_type, NULL, data, match);
11358c2a2b8cSThomas Bogendoerfer 	if (dev)
11368c2a2b8cSThomas Bogendoerfer 		nvmem = to_nvmem_device(dev);
113769aba794SSrinivas Kandagatla 	mutex_unlock(&nvmem_mutex);
1138c7235ee3SBartosz Golaszewski 	if (!nvmem)
1139c7235ee3SBartosz Golaszewski 		return ERR_PTR(-EPROBE_DEFER);
114069aba794SSrinivas Kandagatla 
114169aba794SSrinivas Kandagatla 	if (!try_module_get(nvmem->owner)) {
114269aba794SSrinivas Kandagatla 		dev_err(&nvmem->dev,
114369aba794SSrinivas Kandagatla 			"could not increase module refcount for cell %s\n",
11445db652c9SBartosz Golaszewski 			nvmem_dev_name(nvmem));
114569aba794SSrinivas Kandagatla 
114673e9dc4dSAlban Bedel 		put_device(&nvmem->dev);
114769aba794SSrinivas Kandagatla 		return ERR_PTR(-EINVAL);
114869aba794SSrinivas Kandagatla 	}
114969aba794SSrinivas Kandagatla 
1150c1de7f43SBartosz Golaszewski 	kref_get(&nvmem->refcnt);
1151c1de7f43SBartosz Golaszewski 
115269aba794SSrinivas Kandagatla 	return nvmem;
115369aba794SSrinivas Kandagatla }
115469aba794SSrinivas Kandagatla 
__nvmem_device_put(struct nvmem_device * nvmem)115569aba794SSrinivas Kandagatla static void __nvmem_device_put(struct nvmem_device *nvmem)
115669aba794SSrinivas Kandagatla {
115773e9dc4dSAlban Bedel 	put_device(&nvmem->dev);
115869aba794SSrinivas Kandagatla 	module_put(nvmem->owner);
1159c1de7f43SBartosz Golaszewski 	kref_put(&nvmem->refcnt, nvmem_device_release);
116069aba794SSrinivas Kandagatla }
116169aba794SSrinivas Kandagatla 
1162e701c67cSMasahiro Yamada #if IS_ENABLED(CONFIG_OF)
1163e2a5402eSSrinivas Kandagatla /**
1164e2a5402eSSrinivas Kandagatla  * of_nvmem_device_get() - Get nvmem device from a given id
1165e2a5402eSSrinivas Kandagatla  *
116629143268SVivek Gautam  * @np: Device tree node that uses the nvmem device.
1167e2a5402eSSrinivas Kandagatla  * @id: nvmem name from nvmem-names property.
1168e2a5402eSSrinivas Kandagatla  *
1169e2a5402eSSrinivas Kandagatla  * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device
1170e2a5402eSSrinivas Kandagatla  * on success.
1171e2a5402eSSrinivas Kandagatla  */
of_nvmem_device_get(struct device_node * np,const char * id)1172e2a5402eSSrinivas Kandagatla struct nvmem_device *of_nvmem_device_get(struct device_node *np, const char *id)
1173e2a5402eSSrinivas Kandagatla {
1174e2a5402eSSrinivas Kandagatla 
1175e2a5402eSSrinivas Kandagatla 	struct device_node *nvmem_np;
1176b1c194dcSVadym Kochan 	struct nvmem_device *nvmem;
1177d4e7fef1SAlban Bedel 	int index = 0;
1178e2a5402eSSrinivas Kandagatla 
1179d4e7fef1SAlban Bedel 	if (id)
1180e2a5402eSSrinivas Kandagatla 		index = of_property_match_string(np, "nvmem-names", id);
1181e2a5402eSSrinivas Kandagatla 
1182e2a5402eSSrinivas Kandagatla 	nvmem_np = of_parse_phandle(np, "nvmem", index);
1183e2a5402eSSrinivas Kandagatla 	if (!nvmem_np)
1184d4e7fef1SAlban Bedel 		return ERR_PTR(-ENOENT);
1185e2a5402eSSrinivas Kandagatla 
1186b1c194dcSVadym Kochan 	nvmem = __nvmem_device_get(nvmem_np, device_match_of_node);
1187b1c194dcSVadym Kochan 	of_node_put(nvmem_np);
1188b1c194dcSVadym Kochan 	return nvmem;
1189e2a5402eSSrinivas Kandagatla }
1190e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_nvmem_device_get);
1191e2a5402eSSrinivas Kandagatla #endif
1192e2a5402eSSrinivas Kandagatla 
1193e2a5402eSSrinivas Kandagatla /**
1194e2a5402eSSrinivas Kandagatla  * nvmem_device_get() - Get nvmem device from a given id
1195e2a5402eSSrinivas Kandagatla  *
119629143268SVivek Gautam  * @dev: Device that uses the nvmem device.
119729143268SVivek Gautam  * @dev_name: name of the requested nvmem device.
1198e2a5402eSSrinivas Kandagatla  *
1199e2a5402eSSrinivas Kandagatla  * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device
1200e2a5402eSSrinivas Kandagatla  * on success.
1201e2a5402eSSrinivas Kandagatla  */
nvmem_device_get(struct device * dev,const char * dev_name)1202e2a5402eSSrinivas Kandagatla struct nvmem_device *nvmem_device_get(struct device *dev, const char *dev_name)
1203e2a5402eSSrinivas Kandagatla {
1204e2a5402eSSrinivas Kandagatla 	if (dev->of_node) { /* try dt first */
1205e2a5402eSSrinivas Kandagatla 		struct nvmem_device *nvmem;
1206e2a5402eSSrinivas Kandagatla 
1207e2a5402eSSrinivas Kandagatla 		nvmem = of_nvmem_device_get(dev->of_node, dev_name);
1208e2a5402eSSrinivas Kandagatla 
1209e2a5402eSSrinivas Kandagatla 		if (!IS_ERR(nvmem) || PTR_ERR(nvmem) == -EPROBE_DEFER)
1210e2a5402eSSrinivas Kandagatla 			return nvmem;
1211e2a5402eSSrinivas Kandagatla 
1212e2a5402eSSrinivas Kandagatla 	}
1213e2a5402eSSrinivas Kandagatla 
12148c2a2b8cSThomas Bogendoerfer 	return __nvmem_device_get((void *)dev_name, device_match_name);
1215e2a5402eSSrinivas Kandagatla }
1216e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_get);
1217e2a5402eSSrinivas Kandagatla 
12188c2a2b8cSThomas Bogendoerfer /**
12198c2a2b8cSThomas Bogendoerfer  * nvmem_device_find() - Find nvmem device with matching function
12208c2a2b8cSThomas Bogendoerfer  *
12218c2a2b8cSThomas Bogendoerfer  * @data: Data to pass to match function
12228c2a2b8cSThomas Bogendoerfer  * @match: Callback function to check device
12238c2a2b8cSThomas Bogendoerfer  *
12248c2a2b8cSThomas Bogendoerfer  * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device
12258c2a2b8cSThomas Bogendoerfer  * on success.
12268c2a2b8cSThomas Bogendoerfer  */
nvmem_device_find(void * data,int (* match)(struct device * dev,const void * data))12278c2a2b8cSThomas Bogendoerfer struct nvmem_device *nvmem_device_find(void *data,
12288c2a2b8cSThomas Bogendoerfer 			int (*match)(struct device *dev, const void *data))
12298c2a2b8cSThomas Bogendoerfer {
12308c2a2b8cSThomas Bogendoerfer 	return __nvmem_device_get(data, match);
12318c2a2b8cSThomas Bogendoerfer }
12328c2a2b8cSThomas Bogendoerfer EXPORT_SYMBOL_GPL(nvmem_device_find);
12338c2a2b8cSThomas Bogendoerfer 
devm_nvmem_device_match(struct device * dev,void * res,void * data)1234e2a5402eSSrinivas Kandagatla static int devm_nvmem_device_match(struct device *dev, void *res, void *data)
1235e2a5402eSSrinivas Kandagatla {
1236e2a5402eSSrinivas Kandagatla 	struct nvmem_device **nvmem = res;
1237e2a5402eSSrinivas Kandagatla 
1238e2a5402eSSrinivas Kandagatla 	if (WARN_ON(!nvmem || !*nvmem))
1239e2a5402eSSrinivas Kandagatla 		return 0;
1240e2a5402eSSrinivas Kandagatla 
1241e2a5402eSSrinivas Kandagatla 	return *nvmem == data;
1242e2a5402eSSrinivas Kandagatla }
1243e2a5402eSSrinivas Kandagatla 
devm_nvmem_device_release(struct device * dev,void * res)1244e2a5402eSSrinivas Kandagatla static void devm_nvmem_device_release(struct device *dev, void *res)
1245e2a5402eSSrinivas Kandagatla {
1246e2a5402eSSrinivas Kandagatla 	nvmem_device_put(*(struct nvmem_device **)res);
1247e2a5402eSSrinivas Kandagatla }
1248e2a5402eSSrinivas Kandagatla 
1249e2a5402eSSrinivas Kandagatla /**
1250e2a5402eSSrinivas Kandagatla  * devm_nvmem_device_put() - put alredy got nvmem device
1251e2a5402eSSrinivas Kandagatla  *
125229143268SVivek Gautam  * @dev: Device that uses the nvmem device.
1253e2a5402eSSrinivas Kandagatla  * @nvmem: pointer to nvmem device allocated by devm_nvmem_cell_get(),
1254e2a5402eSSrinivas Kandagatla  * that needs to be released.
1255e2a5402eSSrinivas Kandagatla  */
devm_nvmem_device_put(struct device * dev,struct nvmem_device * nvmem)1256e2a5402eSSrinivas Kandagatla void devm_nvmem_device_put(struct device *dev, struct nvmem_device *nvmem)
1257e2a5402eSSrinivas Kandagatla {
1258e2a5402eSSrinivas Kandagatla 	int ret;
1259e2a5402eSSrinivas Kandagatla 
1260e2a5402eSSrinivas Kandagatla 	ret = devres_release(dev, devm_nvmem_device_release,
1261e2a5402eSSrinivas Kandagatla 			     devm_nvmem_device_match, nvmem);
1262e2a5402eSSrinivas Kandagatla 
1263e2a5402eSSrinivas Kandagatla 	WARN_ON(ret);
1264e2a5402eSSrinivas Kandagatla }
1265e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_device_put);
1266e2a5402eSSrinivas Kandagatla 
1267e2a5402eSSrinivas Kandagatla /**
1268e2a5402eSSrinivas Kandagatla  * nvmem_device_put() - put alredy got nvmem device
1269e2a5402eSSrinivas Kandagatla  *
1270e2a5402eSSrinivas Kandagatla  * @nvmem: pointer to nvmem device that needs to be released.
1271e2a5402eSSrinivas Kandagatla  */
nvmem_device_put(struct nvmem_device * nvmem)1272e2a5402eSSrinivas Kandagatla void nvmem_device_put(struct nvmem_device *nvmem)
1273e2a5402eSSrinivas Kandagatla {
1274e2a5402eSSrinivas Kandagatla 	__nvmem_device_put(nvmem);
1275e2a5402eSSrinivas Kandagatla }
1276e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_put);
1277e2a5402eSSrinivas Kandagatla 
1278e2a5402eSSrinivas Kandagatla /**
1279*c69f37f6SGeert Uytterhoeven  * devm_nvmem_device_get() - Get nvmem device of device form a given id
1280e2a5402eSSrinivas Kandagatla  *
128129143268SVivek Gautam  * @dev: Device that requests the nvmem device.
128229143268SVivek Gautam  * @id: name id for the requested nvmem device.
1283e2a5402eSSrinivas Kandagatla  *
1284*c69f37f6SGeert Uytterhoeven  * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device
1285*c69f37f6SGeert Uytterhoeven  * on success.  The nvmem_device will be freed by the automatically once the
1286e2a5402eSSrinivas Kandagatla  * device is freed.
1287e2a5402eSSrinivas Kandagatla  */
devm_nvmem_device_get(struct device * dev,const char * id)1288e2a5402eSSrinivas Kandagatla struct nvmem_device *devm_nvmem_device_get(struct device *dev, const char *id)
1289e2a5402eSSrinivas Kandagatla {
1290e2a5402eSSrinivas Kandagatla 	struct nvmem_device **ptr, *nvmem;
1291e2a5402eSSrinivas Kandagatla 
1292e2a5402eSSrinivas Kandagatla 	ptr = devres_alloc(devm_nvmem_device_release, sizeof(*ptr), GFP_KERNEL);
1293e2a5402eSSrinivas Kandagatla 	if (!ptr)
1294e2a5402eSSrinivas Kandagatla 		return ERR_PTR(-ENOMEM);
1295e2a5402eSSrinivas Kandagatla 
1296e2a5402eSSrinivas Kandagatla 	nvmem = nvmem_device_get(dev, id);
1297e2a5402eSSrinivas Kandagatla 	if (!IS_ERR(nvmem)) {
1298e2a5402eSSrinivas Kandagatla 		*ptr = nvmem;
1299e2a5402eSSrinivas Kandagatla 		devres_add(dev, ptr);
1300e2a5402eSSrinivas Kandagatla 	} else {
1301e2a5402eSSrinivas Kandagatla 		devres_free(ptr);
1302e2a5402eSSrinivas Kandagatla 	}
1303e2a5402eSSrinivas Kandagatla 
1304e2a5402eSSrinivas Kandagatla 	return nvmem;
1305e2a5402eSSrinivas Kandagatla }
1306e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_device_get);
1307e2a5402eSSrinivas Kandagatla 
nvmem_create_cell(struct nvmem_cell_entry * entry,const char * id,int index)13085d8e6e6cSMichael Walle static struct nvmem_cell *nvmem_create_cell(struct nvmem_cell_entry *entry,
13095d8e6e6cSMichael Walle 					    const char *id, int index)
13107ae6478bSSrinivas Kandagatla {
13117ae6478bSSrinivas Kandagatla 	struct nvmem_cell *cell;
13127ae6478bSSrinivas Kandagatla 	const char *name = NULL;
13137ae6478bSSrinivas Kandagatla 
13147ae6478bSSrinivas Kandagatla 	cell = kzalloc(sizeof(*cell), GFP_KERNEL);
13157ae6478bSSrinivas Kandagatla 	if (!cell)
13167ae6478bSSrinivas Kandagatla 		return ERR_PTR(-ENOMEM);
13177ae6478bSSrinivas Kandagatla 
13187ae6478bSSrinivas Kandagatla 	if (id) {
13197ae6478bSSrinivas Kandagatla 		name = kstrdup_const(id, GFP_KERNEL);
13207ae6478bSSrinivas Kandagatla 		if (!name) {
13217ae6478bSSrinivas Kandagatla 			kfree(cell);
13227ae6478bSSrinivas Kandagatla 			return ERR_PTR(-ENOMEM);
13237ae6478bSSrinivas Kandagatla 		}
13247ae6478bSSrinivas Kandagatla 	}
13257ae6478bSSrinivas Kandagatla 
13267ae6478bSSrinivas Kandagatla 	cell->id = name;
13277ae6478bSSrinivas Kandagatla 	cell->entry = entry;
13285d8e6e6cSMichael Walle 	cell->index = index;
13297ae6478bSSrinivas Kandagatla 
13307ae6478bSSrinivas Kandagatla 	return cell;
13317ae6478bSSrinivas Kandagatla }
13327ae6478bSSrinivas Kandagatla 
1333506157beSBartosz Golaszewski static struct nvmem_cell *
nvmem_cell_get_from_lookup(struct device * dev,const char * con_id)1334506157beSBartosz Golaszewski nvmem_cell_get_from_lookup(struct device *dev, const char *con_id)
133569aba794SSrinivas Kandagatla {
13367ae6478bSSrinivas Kandagatla 	struct nvmem_cell_entry *cell_entry;
1337506157beSBartosz Golaszewski 	struct nvmem_cell *cell = ERR_PTR(-ENOENT);
1338506157beSBartosz Golaszewski 	struct nvmem_cell_lookup *lookup;
133969aba794SSrinivas Kandagatla 	struct nvmem_device *nvmem;
1340506157beSBartosz Golaszewski 	const char *dev_id;
134169aba794SSrinivas Kandagatla 
1342506157beSBartosz Golaszewski 	if (!dev)
1343506157beSBartosz Golaszewski 		return ERR_PTR(-EINVAL);
134469aba794SSrinivas Kandagatla 
1345506157beSBartosz Golaszewski 	dev_id = dev_name(dev);
1346506157beSBartosz Golaszewski 
1347506157beSBartosz Golaszewski 	mutex_lock(&nvmem_lookup_mutex);
1348506157beSBartosz Golaszewski 
1349506157beSBartosz Golaszewski 	list_for_each_entry(lookup, &nvmem_lookup_list, node) {
1350506157beSBartosz Golaszewski 		if ((strcmp(lookup->dev_id, dev_id) == 0) &&
1351506157beSBartosz Golaszewski 		    (strcmp(lookup->con_id, con_id) == 0)) {
1352506157beSBartosz Golaszewski 			/* This is the right entry. */
13538c2a2b8cSThomas Bogendoerfer 			nvmem = __nvmem_device_get((void *)lookup->nvmem_name,
13548c2a2b8cSThomas Bogendoerfer 						   device_match_name);
1355cccb3b19SBartosz Golaszewski 			if (IS_ERR(nvmem)) {
1356506157beSBartosz Golaszewski 				/* Provider may not be registered yet. */
1357cccb3b19SBartosz Golaszewski 				cell = ERR_CAST(nvmem);
13589bfd8198SAlban Bedel 				break;
1359506157beSBartosz Golaszewski 			}
1360506157beSBartosz Golaszewski 
13617ae6478bSSrinivas Kandagatla 			cell_entry = nvmem_find_cell_entry_by_name(nvmem,
1362506157beSBartosz Golaszewski 								   lookup->cell_name);
13637ae6478bSSrinivas Kandagatla 			if (!cell_entry) {
1364506157beSBartosz Golaszewski 				__nvmem_device_put(nvmem);
1365cccb3b19SBartosz Golaszewski 				cell = ERR_PTR(-ENOENT);
13667ae6478bSSrinivas Kandagatla 			} else {
13675d8e6e6cSMichael Walle 				cell = nvmem_create_cell(cell_entry, con_id, 0);
13687ae6478bSSrinivas Kandagatla 				if (IS_ERR(cell))
13697ae6478bSSrinivas Kandagatla 					__nvmem_device_put(nvmem);
1370506157beSBartosz Golaszewski 			}
13719bfd8198SAlban Bedel 			break;
1372506157beSBartosz Golaszewski 		}
1373506157beSBartosz Golaszewski 	}
1374506157beSBartosz Golaszewski 
1375506157beSBartosz Golaszewski 	mutex_unlock(&nvmem_lookup_mutex);
137669aba794SSrinivas Kandagatla 	return cell;
137769aba794SSrinivas Kandagatla }
137869aba794SSrinivas Kandagatla 
nvmem_layout_module_put(struct nvmem_device * nvmem)1379fc29fd82SMiquel Raynal static void nvmem_layout_module_put(struct nvmem_device *nvmem)
1380fc29fd82SMiquel Raynal {
1381fc29fd82SMiquel Raynal 	if (nvmem->layout && nvmem->layout->dev.driver)
1382fc29fd82SMiquel Raynal 		module_put(nvmem->layout->dev.driver->owner);
1383fc29fd82SMiquel Raynal }
1384fc29fd82SMiquel Raynal 
1385e701c67cSMasahiro Yamada #if IS_ENABLED(CONFIG_OF)
13867ae6478bSSrinivas Kandagatla static struct nvmem_cell_entry *
nvmem_find_cell_entry_by_node(struct nvmem_device * nvmem,struct device_node * np)13877ae6478bSSrinivas Kandagatla nvmem_find_cell_entry_by_node(struct nvmem_device *nvmem, struct device_node *np)
13883c53e235SArnd Bergmann {
13897ae6478bSSrinivas Kandagatla 	struct nvmem_cell_entry *iter, *cell = NULL;
13903c53e235SArnd Bergmann 
13913c53e235SArnd Bergmann 	mutex_lock(&nvmem_mutex);
13921c832674SAlban Bedel 	list_for_each_entry(iter, &nvmem->cells, node) {
13931c832674SAlban Bedel 		if (np == iter->np) {
13941c832674SAlban Bedel 			cell = iter;
13953c53e235SArnd Bergmann 			break;
13963c53e235SArnd Bergmann 		}
13971c832674SAlban Bedel 	}
13983c53e235SArnd Bergmann 	mutex_unlock(&nvmem_mutex);
13993c53e235SArnd Bergmann 
14003c53e235SArnd Bergmann 	return cell;
14013c53e235SArnd Bergmann }
14023c53e235SArnd Bergmann 
nvmem_layout_module_get_optional(struct nvmem_device * nvmem)1403fc29fd82SMiquel Raynal static int nvmem_layout_module_get_optional(struct nvmem_device *nvmem)
1404fc29fd82SMiquel Raynal {
1405fc29fd82SMiquel Raynal 	if (!nvmem->layout)
1406fc29fd82SMiquel Raynal 		return 0;
1407fc29fd82SMiquel Raynal 
1408fc29fd82SMiquel Raynal 	if (!nvmem->layout->dev.driver ||
1409fc29fd82SMiquel Raynal 	    !try_module_get(nvmem->layout->dev.driver->owner))
1410fc29fd82SMiquel Raynal 		return -EPROBE_DEFER;
1411fc29fd82SMiquel Raynal 
1412fc29fd82SMiquel Raynal 	return 0;
1413fc29fd82SMiquel Raynal }
1414fc29fd82SMiquel Raynal 
141569aba794SSrinivas Kandagatla /**
141669aba794SSrinivas Kandagatla  * of_nvmem_cell_get() - Get a nvmem cell from given device node and cell id
141769aba794SSrinivas Kandagatla  *
141829143268SVivek Gautam  * @np: Device tree node that uses the nvmem cell.
1419165589f0SBartosz Golaszewski  * @id: nvmem cell name from nvmem-cell-names property, or NULL
1420fd0c478cSVivek Gautam  *      for the cell at index 0 (the lone cell with no accompanying
1421fd0c478cSVivek Gautam  *      nvmem-cell-names property).
142269aba794SSrinivas Kandagatla  *
142369aba794SSrinivas Kandagatla  * Return: Will be an ERR_PTR() on error or a valid pointer
142469aba794SSrinivas Kandagatla  * to a struct nvmem_cell.  The nvmem_cell will be freed by the
142569aba794SSrinivas Kandagatla  * nvmem_cell_put().
142669aba794SSrinivas Kandagatla  */
of_nvmem_cell_get(struct device_node * np,const char * id)1427165589f0SBartosz Golaszewski struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *id)
142869aba794SSrinivas Kandagatla {
142969aba794SSrinivas Kandagatla 	struct device_node *cell_np, *nvmem_np;
143069aba794SSrinivas Kandagatla 	struct nvmem_device *nvmem;
14317ae6478bSSrinivas Kandagatla 	struct nvmem_cell_entry *cell_entry;
1432e888d445SBartosz Golaszewski 	struct nvmem_cell *cell;
14335d8e6e6cSMichael Walle 	struct of_phandle_args cell_spec;
1434fd0c478cSVivek Gautam 	int index = 0;
14355d8e6e6cSMichael Walle 	int cell_index = 0;
14365d8e6e6cSMichael Walle 	int ret;
143769aba794SSrinivas Kandagatla 
1438fd0c478cSVivek Gautam 	/* if cell name exists, find index to the name */
1439165589f0SBartosz Golaszewski 	if (id)
1440165589f0SBartosz Golaszewski 		index = of_property_match_string(np, "nvmem-cell-names", id);
144169aba794SSrinivas Kandagatla 
14425d8e6e6cSMichael Walle 	ret = of_parse_phandle_with_optional_args(np, "nvmem-cells",
14435d8e6e6cSMichael Walle 						  "#nvmem-cell-cells",
14445d8e6e6cSMichael Walle 						  index, &cell_spec);
14455d8e6e6cSMichael Walle 	if (ret)
144606be6208SMichael Walle 		return ERR_PTR(-ENOENT);
14475d8e6e6cSMichael Walle 
14485d8e6e6cSMichael Walle 	if (cell_spec.args_count > 1)
14495d8e6e6cSMichael Walle 		return ERR_PTR(-EINVAL);
14505d8e6e6cSMichael Walle 
14515d8e6e6cSMichael Walle 	cell_np = cell_spec.np;
14525d8e6e6cSMichael Walle 	if (cell_spec.args_count)
14535d8e6e6cSMichael Walle 		cell_index = cell_spec.args[0];
145469aba794SSrinivas Kandagatla 
1455edcf2fb6SMichael Walle 	nvmem_np = of_get_parent(cell_np);
1456edcf2fb6SMichael Walle 	if (!nvmem_np) {
1457edcf2fb6SMichael Walle 		of_node_put(cell_np);
145869aba794SSrinivas Kandagatla 		return ERR_PTR(-EINVAL);
1459edcf2fb6SMichael Walle 	}
146069aba794SSrinivas Kandagatla 
1461266570f4SMichael Walle 	/* nvmem layouts produce cells within the nvmem-layout container */
1462266570f4SMichael Walle 	if (of_node_name_eq(nvmem_np, "nvmem-layout")) {
1463266570f4SMichael Walle 		nvmem_np = of_get_next_parent(nvmem_np);
1464266570f4SMichael Walle 		if (!nvmem_np) {
1465266570f4SMichael Walle 			of_node_put(cell_np);
1466266570f4SMichael Walle 			return ERR_PTR(-EINVAL);
1467266570f4SMichael Walle 		}
1468266570f4SMichael Walle 	}
1469266570f4SMichael Walle 
14708c2a2b8cSThomas Bogendoerfer 	nvmem = __nvmem_device_get(nvmem_np, device_match_of_node);
1471aad8d097SMasahiro Yamada 	of_node_put(nvmem_np);
1472edcf2fb6SMichael Walle 	if (IS_ERR(nvmem)) {
1473edcf2fb6SMichael Walle 		of_node_put(cell_np);
147469aba794SSrinivas Kandagatla 		return ERR_CAST(nvmem);
1475edcf2fb6SMichael Walle 	}
147669aba794SSrinivas Kandagatla 
1477fc29fd82SMiquel Raynal 	ret = nvmem_layout_module_get_optional(nvmem);
1478fc29fd82SMiquel Raynal 	if (ret) {
1479fc29fd82SMiquel Raynal 		of_node_put(cell_np);
1480fc29fd82SMiquel Raynal 		__nvmem_device_put(nvmem);
1481fc29fd82SMiquel Raynal 		return ERR_PTR(ret);
1482fc29fd82SMiquel Raynal 	}
1483fc29fd82SMiquel Raynal 
14847ae6478bSSrinivas Kandagatla 	cell_entry = nvmem_find_cell_entry_by_node(nvmem, cell_np);
1485edcf2fb6SMichael Walle 	of_node_put(cell_np);
14867ae6478bSSrinivas Kandagatla 	if (!cell_entry) {
1487e888d445SBartosz Golaszewski 		__nvmem_device_put(nvmem);
1488fc29fd82SMiquel Raynal 		nvmem_layout_module_put(nvmem);
1489fc29fd82SMiquel Raynal 		if (nvmem->layout)
1490fc29fd82SMiquel Raynal 			return ERR_PTR(-EPROBE_DEFER);
1491fc29fd82SMiquel Raynal 		else
1492e888d445SBartosz Golaszewski 			return ERR_PTR(-ENOENT);
149369aba794SSrinivas Kandagatla 	}
149469aba794SSrinivas Kandagatla 
14955d8e6e6cSMichael Walle 	cell = nvmem_create_cell(cell_entry, id, cell_index);
1496fc29fd82SMiquel Raynal 	if (IS_ERR(cell)) {
14977ae6478bSSrinivas Kandagatla 		__nvmem_device_put(nvmem);
1498fc29fd82SMiquel Raynal 		nvmem_layout_module_put(nvmem);
1499fc29fd82SMiquel Raynal 	}
15007ae6478bSSrinivas Kandagatla 
150169aba794SSrinivas Kandagatla 	return cell;
150269aba794SSrinivas Kandagatla }
150369aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_nvmem_cell_get);
150469aba794SSrinivas Kandagatla #endif
150569aba794SSrinivas Kandagatla 
150669aba794SSrinivas Kandagatla /**
150769aba794SSrinivas Kandagatla  * nvmem_cell_get() - Get nvmem cell of device form a given cell name
150869aba794SSrinivas Kandagatla  *
150929143268SVivek Gautam  * @dev: Device that requests the nvmem cell.
1510165589f0SBartosz Golaszewski  * @id: nvmem cell name to get (this corresponds with the name from the
1511165589f0SBartosz Golaszewski  *      nvmem-cell-names property for DT systems and with the con_id from
1512165589f0SBartosz Golaszewski  *      the lookup entry for non-DT systems).
151369aba794SSrinivas Kandagatla  *
151469aba794SSrinivas Kandagatla  * Return: Will be an ERR_PTR() on error or a valid pointer
151569aba794SSrinivas Kandagatla  * to a struct nvmem_cell.  The nvmem_cell will be freed by the
151669aba794SSrinivas Kandagatla  * nvmem_cell_put().
151769aba794SSrinivas Kandagatla  */
nvmem_cell_get(struct device * dev,const char * id)1518165589f0SBartosz Golaszewski struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *id)
151969aba794SSrinivas Kandagatla {
152069aba794SSrinivas Kandagatla 	struct nvmem_cell *cell;
152169aba794SSrinivas Kandagatla 
152269aba794SSrinivas Kandagatla 	if (dev->of_node) { /* try dt first */
1523165589f0SBartosz Golaszewski 		cell = of_nvmem_cell_get(dev->of_node, id);
152469aba794SSrinivas Kandagatla 		if (!IS_ERR(cell) || PTR_ERR(cell) == -EPROBE_DEFER)
152569aba794SSrinivas Kandagatla 			return cell;
152669aba794SSrinivas Kandagatla 	}
152769aba794SSrinivas Kandagatla 
1528165589f0SBartosz Golaszewski 	/* NULL cell id only allowed for device tree; invalid otherwise */
1529165589f0SBartosz Golaszewski 	if (!id)
153087ed1405SDouglas Anderson 		return ERR_PTR(-EINVAL);
153187ed1405SDouglas Anderson 
1532165589f0SBartosz Golaszewski 	return nvmem_cell_get_from_lookup(dev, id);
153369aba794SSrinivas Kandagatla }
153469aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_get);
153569aba794SSrinivas Kandagatla 
devm_nvmem_cell_release(struct device * dev,void * res)153669aba794SSrinivas Kandagatla static void devm_nvmem_cell_release(struct device *dev, void *res)
153769aba794SSrinivas Kandagatla {
153869aba794SSrinivas Kandagatla 	nvmem_cell_put(*(struct nvmem_cell **)res);
153969aba794SSrinivas Kandagatla }
154069aba794SSrinivas Kandagatla 
154169aba794SSrinivas Kandagatla /**
154269aba794SSrinivas Kandagatla  * devm_nvmem_cell_get() - Get nvmem cell of device form a given id
154369aba794SSrinivas Kandagatla  *
154429143268SVivek Gautam  * @dev: Device that requests the nvmem cell.
154529143268SVivek Gautam  * @id: nvmem cell name id to get.
154669aba794SSrinivas Kandagatla  *
154769aba794SSrinivas Kandagatla  * Return: Will be an ERR_PTR() on error or a valid pointer
154869aba794SSrinivas Kandagatla  * to a struct nvmem_cell.  The nvmem_cell will be freed by the
154969aba794SSrinivas Kandagatla  * automatically once the device is freed.
155069aba794SSrinivas Kandagatla  */
devm_nvmem_cell_get(struct device * dev,const char * id)155169aba794SSrinivas Kandagatla struct nvmem_cell *devm_nvmem_cell_get(struct device *dev, const char *id)
155269aba794SSrinivas Kandagatla {
155369aba794SSrinivas Kandagatla 	struct nvmem_cell **ptr, *cell;
155469aba794SSrinivas Kandagatla 
155569aba794SSrinivas Kandagatla 	ptr = devres_alloc(devm_nvmem_cell_release, sizeof(*ptr), GFP_KERNEL);
155669aba794SSrinivas Kandagatla 	if (!ptr)
155769aba794SSrinivas Kandagatla 		return ERR_PTR(-ENOMEM);
155869aba794SSrinivas Kandagatla 
155969aba794SSrinivas Kandagatla 	cell = nvmem_cell_get(dev, id);
156069aba794SSrinivas Kandagatla 	if (!IS_ERR(cell)) {
156169aba794SSrinivas Kandagatla 		*ptr = cell;
156269aba794SSrinivas Kandagatla 		devres_add(dev, ptr);
156369aba794SSrinivas Kandagatla 	} else {
156469aba794SSrinivas Kandagatla 		devres_free(ptr);
156569aba794SSrinivas Kandagatla 	}
156669aba794SSrinivas Kandagatla 
156769aba794SSrinivas Kandagatla 	return cell;
156869aba794SSrinivas Kandagatla }
156969aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_cell_get);
157069aba794SSrinivas Kandagatla 
devm_nvmem_cell_match(struct device * dev,void * res,void * data)157169aba794SSrinivas Kandagatla static int devm_nvmem_cell_match(struct device *dev, void *res, void *data)
157269aba794SSrinivas Kandagatla {
157369aba794SSrinivas Kandagatla 	struct nvmem_cell **c = res;
157469aba794SSrinivas Kandagatla 
157569aba794SSrinivas Kandagatla 	if (WARN_ON(!c || !*c))
157669aba794SSrinivas Kandagatla 		return 0;
157769aba794SSrinivas Kandagatla 
157869aba794SSrinivas Kandagatla 	return *c == data;
157969aba794SSrinivas Kandagatla }
158069aba794SSrinivas Kandagatla 
158169aba794SSrinivas Kandagatla /**
158269aba794SSrinivas Kandagatla  * devm_nvmem_cell_put() - Release previously allocated nvmem cell
158369aba794SSrinivas Kandagatla  * from devm_nvmem_cell_get.
158469aba794SSrinivas Kandagatla  *
158529143268SVivek Gautam  * @dev: Device that requests the nvmem cell.
158629143268SVivek Gautam  * @cell: Previously allocated nvmem cell by devm_nvmem_cell_get().
158769aba794SSrinivas Kandagatla  */
devm_nvmem_cell_put(struct device * dev,struct nvmem_cell * cell)158869aba794SSrinivas Kandagatla void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell)
158969aba794SSrinivas Kandagatla {
159069aba794SSrinivas Kandagatla 	int ret;
159169aba794SSrinivas Kandagatla 
159269aba794SSrinivas Kandagatla 	ret = devres_release(dev, devm_nvmem_cell_release,
159369aba794SSrinivas Kandagatla 				devm_nvmem_cell_match, cell);
159469aba794SSrinivas Kandagatla 
159569aba794SSrinivas Kandagatla 	WARN_ON(ret);
159669aba794SSrinivas Kandagatla }
159769aba794SSrinivas Kandagatla EXPORT_SYMBOL(devm_nvmem_cell_put);
159869aba794SSrinivas Kandagatla 
159969aba794SSrinivas Kandagatla /**
160069aba794SSrinivas Kandagatla  * nvmem_cell_put() - Release previously allocated nvmem cell.
160169aba794SSrinivas Kandagatla  *
160229143268SVivek Gautam  * @cell: Previously allocated nvmem cell by nvmem_cell_get().
160369aba794SSrinivas Kandagatla  */
nvmem_cell_put(struct nvmem_cell * cell)160469aba794SSrinivas Kandagatla void nvmem_cell_put(struct nvmem_cell *cell)
160569aba794SSrinivas Kandagatla {
16067ae6478bSSrinivas Kandagatla 	struct nvmem_device *nvmem = cell->entry->nvmem;
160769aba794SSrinivas Kandagatla 
16087ae6478bSSrinivas Kandagatla 	if (cell->id)
16097ae6478bSSrinivas Kandagatla 		kfree_const(cell->id);
16107ae6478bSSrinivas Kandagatla 
16117ae6478bSSrinivas Kandagatla 	kfree(cell);
161269aba794SSrinivas Kandagatla 	__nvmem_device_put(nvmem);
1613fc29fd82SMiquel Raynal 	nvmem_layout_module_put(nvmem);
161469aba794SSrinivas Kandagatla }
161569aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_put);
161669aba794SSrinivas Kandagatla 
nvmem_shift_read_buffer_in_place(struct nvmem_cell_entry * cell,void * buf)16177ae6478bSSrinivas Kandagatla static void nvmem_shift_read_buffer_in_place(struct nvmem_cell_entry *cell, void *buf)
161869aba794SSrinivas Kandagatla {
161969aba794SSrinivas Kandagatla 	u8 *p, *b;
16202fe518feSJorge Ramirez-Ortiz 	int i, extra, bit_offset = cell->bit_offset;
162169aba794SSrinivas Kandagatla 
162269aba794SSrinivas Kandagatla 	p = b = buf;
162369aba794SSrinivas Kandagatla 	if (bit_offset) {
162469aba794SSrinivas Kandagatla 		/* First shift */
162569aba794SSrinivas Kandagatla 		*b++ >>= bit_offset;
162669aba794SSrinivas Kandagatla 
162769aba794SSrinivas Kandagatla 		/* setup rest of the bytes if any */
162869aba794SSrinivas Kandagatla 		for (i = 1; i < cell->bytes; i++) {
162969aba794SSrinivas Kandagatla 			/* Get bits from next byte and shift them towards msb */
163069aba794SSrinivas Kandagatla 			*p |= *b << (BITS_PER_BYTE - bit_offset);
163169aba794SSrinivas Kandagatla 
163269aba794SSrinivas Kandagatla 			p = b;
163369aba794SSrinivas Kandagatla 			*b++ >>= bit_offset;
163469aba794SSrinivas Kandagatla 		}
16352fe518feSJorge Ramirez-Ortiz 	} else {
16362fe518feSJorge Ramirez-Ortiz 		/* point to the msb */
16372fe518feSJorge Ramirez-Ortiz 		p += cell->bytes - 1;
16382fe518feSJorge Ramirez-Ortiz 	}
163969aba794SSrinivas Kandagatla 
164069aba794SSrinivas Kandagatla 	/* result fits in less bytes */
16412fe518feSJorge Ramirez-Ortiz 	extra = cell->bytes - DIV_ROUND_UP(cell->nbits, BITS_PER_BYTE);
16422fe518feSJorge Ramirez-Ortiz 	while (--extra >= 0)
164369aba794SSrinivas Kandagatla 		*p-- = 0;
16442fe518feSJorge Ramirez-Ortiz 
164569aba794SSrinivas Kandagatla 	/* clear msb bits if any leftover in the last byte */
16465d388fa0SStephen Boyd 	if (cell->nbits % BITS_PER_BYTE)
164769aba794SSrinivas Kandagatla 		*p &= GENMASK((cell->nbits % BITS_PER_BYTE) - 1, 0);
164869aba794SSrinivas Kandagatla }
164969aba794SSrinivas Kandagatla 
__nvmem_cell_read(struct nvmem_device * nvmem,struct nvmem_cell_entry * cell,void * buf,size_t * len,const char * id,int index)165069aba794SSrinivas Kandagatla static int __nvmem_cell_read(struct nvmem_device *nvmem,
16517ae6478bSSrinivas Kandagatla 			     struct nvmem_cell_entry *cell,
16525d8e6e6cSMichael Walle 			     void *buf, size_t *len, const char *id, int index)
165369aba794SSrinivas Kandagatla {
165469aba794SSrinivas Kandagatla 	int rc;
165569aba794SSrinivas Kandagatla 
165655d4980cSRafał Miłecki 	rc = nvmem_reg_read(nvmem, cell->offset, buf, cell->raw_len);
165769aba794SSrinivas Kandagatla 
1658287980e4SArnd Bergmann 	if (rc)
165969aba794SSrinivas Kandagatla 		return rc;
166069aba794SSrinivas Kandagatla 
166169aba794SSrinivas Kandagatla 	/* shift bits in-place */
1662cbf854abSAxel Lin 	if (cell->bit_offset || cell->nbits)
166369aba794SSrinivas Kandagatla 		nvmem_shift_read_buffer_in_place(cell, buf);
166469aba794SSrinivas Kandagatla 
1665345ec382SMichael Walle 	if (cell->read_post_process) {
16668a134fd9SMichael Walle 		rc = cell->read_post_process(cell->priv, id, index,
166755d4980cSRafał Miłecki 					     cell->offset, buf, cell->raw_len);
1668345ec382SMichael Walle 		if (rc)
1669345ec382SMichael Walle 			return rc;
1670345ec382SMichael Walle 	}
1671345ec382SMichael Walle 
16723b4a6877SVivek Gautam 	if (len)
167369aba794SSrinivas Kandagatla 		*len = cell->bytes;
167469aba794SSrinivas Kandagatla 
167569aba794SSrinivas Kandagatla 	return 0;
167669aba794SSrinivas Kandagatla }
167769aba794SSrinivas Kandagatla 
167869aba794SSrinivas Kandagatla /**
167969aba794SSrinivas Kandagatla  * nvmem_cell_read() - Read a given nvmem cell
168069aba794SSrinivas Kandagatla  *
168169aba794SSrinivas Kandagatla  * @cell: nvmem cell to be read.
16823b4a6877SVivek Gautam  * @len: pointer to length of cell which will be populated on successful read;
16833b4a6877SVivek Gautam  *	 can be NULL.
168469aba794SSrinivas Kandagatla  *
1685b577fafcSBrian Norris  * Return: ERR_PTR() on error or a valid pointer to a buffer on success. The
1686b577fafcSBrian Norris  * buffer should be freed by the consumer with a kfree().
168769aba794SSrinivas Kandagatla  */
nvmem_cell_read(struct nvmem_cell * cell,size_t * len)168869aba794SSrinivas Kandagatla void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len)
168969aba794SSrinivas Kandagatla {
169055d4980cSRafał Miłecki 	struct nvmem_cell_entry *entry = cell->entry;
169155d4980cSRafał Miłecki 	struct nvmem_device *nvmem = entry->nvmem;
169269aba794SSrinivas Kandagatla 	u8 *buf;
169369aba794SSrinivas Kandagatla 	int rc;
169469aba794SSrinivas Kandagatla 
1695795ddd18SSrinivas Kandagatla 	if (!nvmem)
169669aba794SSrinivas Kandagatla 		return ERR_PTR(-EINVAL);
169769aba794SSrinivas Kandagatla 
169855d4980cSRafał Miłecki 	buf = kzalloc(max_t(size_t, entry->raw_len, entry->bytes), GFP_KERNEL);
169969aba794SSrinivas Kandagatla 	if (!buf)
170069aba794SSrinivas Kandagatla 		return ERR_PTR(-ENOMEM);
170169aba794SSrinivas Kandagatla 
17025d8e6e6cSMichael Walle 	rc = __nvmem_cell_read(nvmem, cell->entry, buf, len, cell->id, cell->index);
1703287980e4SArnd Bergmann 	if (rc) {
170469aba794SSrinivas Kandagatla 		kfree(buf);
170569aba794SSrinivas Kandagatla 		return ERR_PTR(rc);
170669aba794SSrinivas Kandagatla 	}
170769aba794SSrinivas Kandagatla 
170869aba794SSrinivas Kandagatla 	return buf;
170969aba794SSrinivas Kandagatla }
171069aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_read);
171169aba794SSrinivas Kandagatla 
nvmem_cell_prepare_write_buffer(struct nvmem_cell_entry * cell,u8 * _buf,int len)17127ae6478bSSrinivas Kandagatla static void *nvmem_cell_prepare_write_buffer(struct nvmem_cell_entry *cell,
171369aba794SSrinivas Kandagatla 					     u8 *_buf, int len)
171469aba794SSrinivas Kandagatla {
171569aba794SSrinivas Kandagatla 	struct nvmem_device *nvmem = cell->nvmem;
171669aba794SSrinivas Kandagatla 	int i, rc, nbits, bit_offset = cell->bit_offset;
171769aba794SSrinivas Kandagatla 	u8 v, *p, *buf, *b, pbyte, pbits;
171869aba794SSrinivas Kandagatla 
171969aba794SSrinivas Kandagatla 	nbits = cell->nbits;
172069aba794SSrinivas Kandagatla 	buf = kzalloc(cell->bytes, GFP_KERNEL);
172169aba794SSrinivas Kandagatla 	if (!buf)
172269aba794SSrinivas Kandagatla 		return ERR_PTR(-ENOMEM);
172369aba794SSrinivas Kandagatla 
172469aba794SSrinivas Kandagatla 	memcpy(buf, _buf, len);
172569aba794SSrinivas Kandagatla 	p = b = buf;
172669aba794SSrinivas Kandagatla 
172769aba794SSrinivas Kandagatla 	if (bit_offset) {
172869aba794SSrinivas Kandagatla 		pbyte = *b;
172969aba794SSrinivas Kandagatla 		*b <<= bit_offset;
173069aba794SSrinivas Kandagatla 
173169aba794SSrinivas Kandagatla 		/* setup the first byte with lsb bits from nvmem */
1732795ddd18SSrinivas Kandagatla 		rc = nvmem_reg_read(nvmem, cell->offset, &v, 1);
173350808bfcSMathieu Malaterre 		if (rc)
173450808bfcSMathieu Malaterre 			goto err;
173569aba794SSrinivas Kandagatla 		*b++ |= GENMASK(bit_offset - 1, 0) & v;
173669aba794SSrinivas Kandagatla 
173769aba794SSrinivas Kandagatla 		/* setup rest of the byte if any */
173869aba794SSrinivas Kandagatla 		for (i = 1; i < cell->bytes; i++) {
173969aba794SSrinivas Kandagatla 			/* Get last byte bits and shift them towards lsb */
174069aba794SSrinivas Kandagatla 			pbits = pbyte >> (BITS_PER_BYTE - 1 - bit_offset);
174169aba794SSrinivas Kandagatla 			pbyte = *b;
174269aba794SSrinivas Kandagatla 			p = b;
174369aba794SSrinivas Kandagatla 			*b <<= bit_offset;
174469aba794SSrinivas Kandagatla 			*b++ |= pbits;
174569aba794SSrinivas Kandagatla 		}
174669aba794SSrinivas Kandagatla 	}
174769aba794SSrinivas Kandagatla 
174869aba794SSrinivas Kandagatla 	/* if it's not end on byte boundary */
174969aba794SSrinivas Kandagatla 	if ((nbits + bit_offset) % BITS_PER_BYTE) {
175069aba794SSrinivas Kandagatla 		/* setup the last byte with msb bits from nvmem */
1751795ddd18SSrinivas Kandagatla 		rc = nvmem_reg_read(nvmem,
175269aba794SSrinivas Kandagatla 				    cell->offset + cell->bytes - 1, &v, 1);
175350808bfcSMathieu Malaterre 		if (rc)
175450808bfcSMathieu Malaterre 			goto err;
175569aba794SSrinivas Kandagatla 		*p |= GENMASK(7, (nbits + bit_offset) % BITS_PER_BYTE) & v;
175669aba794SSrinivas Kandagatla 
175769aba794SSrinivas Kandagatla 	}
175869aba794SSrinivas Kandagatla 
175969aba794SSrinivas Kandagatla 	return buf;
176050808bfcSMathieu Malaterre err:
176150808bfcSMathieu Malaterre 	kfree(buf);
176250808bfcSMathieu Malaterre 	return ERR_PTR(rc);
176369aba794SSrinivas Kandagatla }
176469aba794SSrinivas Kandagatla 
__nvmem_cell_entry_write(struct nvmem_cell_entry * cell,void * buf,size_t len)17657ae6478bSSrinivas Kandagatla static int __nvmem_cell_entry_write(struct nvmem_cell_entry *cell, void *buf, size_t len)
176669aba794SSrinivas Kandagatla {
176769aba794SSrinivas Kandagatla 	struct nvmem_device *nvmem = cell->nvmem;
176869aba794SSrinivas Kandagatla 	int rc;
176969aba794SSrinivas Kandagatla 
1770795ddd18SSrinivas Kandagatla 	if (!nvmem || nvmem->read_only ||
177169aba794SSrinivas Kandagatla 	    (cell->bit_offset == 0 && len != cell->bytes))
177269aba794SSrinivas Kandagatla 		return -EINVAL;
177369aba794SSrinivas Kandagatla 
1774345ec382SMichael Walle 	/*
1775345ec382SMichael Walle 	 * Any cells which have a read_post_process hook are read-only because
1776345ec382SMichael Walle 	 * we cannot reverse the operation and it might affect other cells,
1777345ec382SMichael Walle 	 * too.
1778345ec382SMichael Walle 	 */
1779345ec382SMichael Walle 	if (cell->read_post_process)
1780345ec382SMichael Walle 		return -EINVAL;
1781345ec382SMichael Walle 
178269aba794SSrinivas Kandagatla 	if (cell->bit_offset || cell->nbits) {
178369aba794SSrinivas Kandagatla 		buf = nvmem_cell_prepare_write_buffer(cell, buf, len);
178469aba794SSrinivas Kandagatla 		if (IS_ERR(buf))
178569aba794SSrinivas Kandagatla 			return PTR_ERR(buf);
178669aba794SSrinivas Kandagatla 	}
178769aba794SSrinivas Kandagatla 
1788795ddd18SSrinivas Kandagatla 	rc = nvmem_reg_write(nvmem, cell->offset, buf, cell->bytes);
178969aba794SSrinivas Kandagatla 
179069aba794SSrinivas Kandagatla 	/* free the tmp buffer */
1791ace22170SAxel Lin 	if (cell->bit_offset || cell->nbits)
179269aba794SSrinivas Kandagatla 		kfree(buf);
179369aba794SSrinivas Kandagatla 
1794287980e4SArnd Bergmann 	if (rc)
179569aba794SSrinivas Kandagatla 		return rc;
179669aba794SSrinivas Kandagatla 
179769aba794SSrinivas Kandagatla 	return len;
179869aba794SSrinivas Kandagatla }
17997ae6478bSSrinivas Kandagatla 
18007ae6478bSSrinivas Kandagatla /**
18017ae6478bSSrinivas Kandagatla  * nvmem_cell_write() - Write to a given nvmem cell
18027ae6478bSSrinivas Kandagatla  *
18037ae6478bSSrinivas Kandagatla  * @cell: nvmem cell to be written.
18047ae6478bSSrinivas Kandagatla  * @buf: Buffer to be written.
18057ae6478bSSrinivas Kandagatla  * @len: length of buffer to be written to nvmem cell.
18067ae6478bSSrinivas Kandagatla  *
18077ae6478bSSrinivas Kandagatla  * Return: length of bytes written or negative on failure.
18087ae6478bSSrinivas Kandagatla  */
nvmem_cell_write(struct nvmem_cell * cell,void * buf,size_t len)18097ae6478bSSrinivas Kandagatla int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len)
18107ae6478bSSrinivas Kandagatla {
18117ae6478bSSrinivas Kandagatla 	return __nvmem_cell_entry_write(cell->entry, buf, len);
18127ae6478bSSrinivas Kandagatla }
18137ae6478bSSrinivas Kandagatla 
181469aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_write);
181569aba794SSrinivas Kandagatla 
nvmem_cell_read_common(struct device * dev,const char * cell_id,void * val,size_t count)18166bb317ceSYangtao Li static int nvmem_cell_read_common(struct device *dev, const char *cell_id,
18176bb317ceSYangtao Li 				  void *val, size_t count)
18180a9b2d1cSFabrice Gasnier {
18190a9b2d1cSFabrice Gasnier 	struct nvmem_cell *cell;
18200a9b2d1cSFabrice Gasnier 	void *buf;
18210a9b2d1cSFabrice Gasnier 	size_t len;
18220a9b2d1cSFabrice Gasnier 
18230a9b2d1cSFabrice Gasnier 	cell = nvmem_cell_get(dev, cell_id);
18240a9b2d1cSFabrice Gasnier 	if (IS_ERR(cell))
18250a9b2d1cSFabrice Gasnier 		return PTR_ERR(cell);
18260a9b2d1cSFabrice Gasnier 
18270a9b2d1cSFabrice Gasnier 	buf = nvmem_cell_read(cell, &len);
18280a9b2d1cSFabrice Gasnier 	if (IS_ERR(buf)) {
18290a9b2d1cSFabrice Gasnier 		nvmem_cell_put(cell);
18300a9b2d1cSFabrice Gasnier 		return PTR_ERR(buf);
18310a9b2d1cSFabrice Gasnier 	}
18326bb317ceSYangtao Li 	if (len != count) {
18330a9b2d1cSFabrice Gasnier 		kfree(buf);
18340a9b2d1cSFabrice Gasnier 		nvmem_cell_put(cell);
18350a9b2d1cSFabrice Gasnier 		return -EINVAL;
18360a9b2d1cSFabrice Gasnier 	}
18376bb317ceSYangtao Li 	memcpy(val, buf, count);
18380a9b2d1cSFabrice Gasnier 	kfree(buf);
18390a9b2d1cSFabrice Gasnier 	nvmem_cell_put(cell);
18400a9b2d1cSFabrice Gasnier 
18410a9b2d1cSFabrice Gasnier 	return 0;
18420a9b2d1cSFabrice Gasnier }
18436bb317ceSYangtao Li 
18446bb317ceSYangtao Li /**
18455037d368SAndreas Färber  * nvmem_cell_read_u8() - Read a cell value as a u8
18465037d368SAndreas Färber  *
18475037d368SAndreas Färber  * @dev: Device that requests the nvmem cell.
18485037d368SAndreas Färber  * @cell_id: Name of nvmem cell to read.
18495037d368SAndreas Färber  * @val: pointer to output value.
18505037d368SAndreas Färber  *
18515037d368SAndreas Färber  * Return: 0 on success or negative errno.
18525037d368SAndreas Färber  */
nvmem_cell_read_u8(struct device * dev,const char * cell_id,u8 * val)18535037d368SAndreas Färber int nvmem_cell_read_u8(struct device *dev, const char *cell_id, u8 *val)
18545037d368SAndreas Färber {
18555037d368SAndreas Färber 	return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val));
18565037d368SAndreas Färber }
18575037d368SAndreas Färber EXPORT_SYMBOL_GPL(nvmem_cell_read_u8);
18585037d368SAndreas Färber 
18595037d368SAndreas Färber /**
18603a758071SAndreas Färber  * nvmem_cell_read_u16() - Read a cell value as a u16
18616bb317ceSYangtao Li  *
18626bb317ceSYangtao Li  * @dev: Device that requests the nvmem cell.
18636bb317ceSYangtao Li  * @cell_id: Name of nvmem cell to read.
18646bb317ceSYangtao Li  * @val: pointer to output value.
18656bb317ceSYangtao Li  *
18666bb317ceSYangtao Li  * Return: 0 on success or negative errno.
18676bb317ceSYangtao Li  */
nvmem_cell_read_u16(struct device * dev,const char * cell_id,u16 * val)18686bb317ceSYangtao Li int nvmem_cell_read_u16(struct device *dev, const char *cell_id, u16 *val)
18696bb317ceSYangtao Li {
18706bb317ceSYangtao Li 	return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val));
18716bb317ceSYangtao Li }
18720a9b2d1cSFabrice Gasnier EXPORT_SYMBOL_GPL(nvmem_cell_read_u16);
18730a9b2d1cSFabrice Gasnier 
18740a9b2d1cSFabrice Gasnier /**
18753a758071SAndreas Färber  * nvmem_cell_read_u32() - Read a cell value as a u32
1876d026d70aSLeonard Crestez  *
1877d026d70aSLeonard Crestez  * @dev: Device that requests the nvmem cell.
1878d026d70aSLeonard Crestez  * @cell_id: Name of nvmem cell to read.
1879d026d70aSLeonard Crestez  * @val: pointer to output value.
1880d026d70aSLeonard Crestez  *
1881d026d70aSLeonard Crestez  * Return: 0 on success or negative errno.
1882d026d70aSLeonard Crestez  */
nvmem_cell_read_u32(struct device * dev,const char * cell_id,u32 * val)1883d026d70aSLeonard Crestez int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val)
1884d026d70aSLeonard Crestez {
18856bb317ceSYangtao Li 	return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val));
1886d026d70aSLeonard Crestez }
1887d026d70aSLeonard Crestez EXPORT_SYMBOL_GPL(nvmem_cell_read_u32);
1888d026d70aSLeonard Crestez 
1889d026d70aSLeonard Crestez /**
18903a758071SAndreas Färber  * nvmem_cell_read_u64() - Read a cell value as a u64
18918b977c54SYangtao Li  *
18928b977c54SYangtao Li  * @dev: Device that requests the nvmem cell.
18938b977c54SYangtao Li  * @cell_id: Name of nvmem cell to read.
18948b977c54SYangtao Li  * @val: pointer to output value.
18958b977c54SYangtao Li  *
18968b977c54SYangtao Li  * Return: 0 on success or negative errno.
18978b977c54SYangtao Li  */
nvmem_cell_read_u64(struct device * dev,const char * cell_id,u64 * val)18988b977c54SYangtao Li int nvmem_cell_read_u64(struct device *dev, const char *cell_id, u64 *val)
18998b977c54SYangtao Li {
19008b977c54SYangtao Li 	return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val));
19018b977c54SYangtao Li }
19028b977c54SYangtao Li EXPORT_SYMBOL_GPL(nvmem_cell_read_u64);
19038b977c54SYangtao Li 
nvmem_cell_read_variable_common(struct device * dev,const char * cell_id,size_t max_len,size_t * len)19041f7b4d87SDouglas Anderson static const void *nvmem_cell_read_variable_common(struct device *dev,
1905a28e824fSDouglas Anderson 						   const char *cell_id,
1906a28e824fSDouglas Anderson 						   size_t max_len, size_t *len)
1907a28e824fSDouglas Anderson {
1908a28e824fSDouglas Anderson 	struct nvmem_cell *cell;
1909a28e824fSDouglas Anderson 	int nbits;
1910a28e824fSDouglas Anderson 	void *buf;
1911a28e824fSDouglas Anderson 
1912a28e824fSDouglas Anderson 	cell = nvmem_cell_get(dev, cell_id);
1913a28e824fSDouglas Anderson 	if (IS_ERR(cell))
1914a28e824fSDouglas Anderson 		return cell;
1915a28e824fSDouglas Anderson 
19167ae6478bSSrinivas Kandagatla 	nbits = cell->entry->nbits;
1917a28e824fSDouglas Anderson 	buf = nvmem_cell_read(cell, len);
1918a28e824fSDouglas Anderson 	nvmem_cell_put(cell);
1919a28e824fSDouglas Anderson 	if (IS_ERR(buf))
1920a28e824fSDouglas Anderson 		return buf;
1921a28e824fSDouglas Anderson 
1922a28e824fSDouglas Anderson 	/*
1923a28e824fSDouglas Anderson 	 * If nbits is set then nvmem_cell_read() can significantly exaggerate
1924a28e824fSDouglas Anderson 	 * the length of the real data. Throw away the extra junk.
1925a28e824fSDouglas Anderson 	 */
1926a28e824fSDouglas Anderson 	if (nbits)
1927a28e824fSDouglas Anderson 		*len = DIV_ROUND_UP(nbits, 8);
1928a28e824fSDouglas Anderson 
1929a28e824fSDouglas Anderson 	if (*len > max_len) {
1930a28e824fSDouglas Anderson 		kfree(buf);
1931a28e824fSDouglas Anderson 		return ERR_PTR(-ERANGE);
1932a28e824fSDouglas Anderson 	}
1933a28e824fSDouglas Anderson 
1934a28e824fSDouglas Anderson 	return buf;
1935a28e824fSDouglas Anderson }
1936a28e824fSDouglas Anderson 
1937a28e824fSDouglas Anderson /**
1938a28e824fSDouglas Anderson  * nvmem_cell_read_variable_le_u32() - Read up to 32-bits of data as a little endian number.
1939a28e824fSDouglas Anderson  *
1940a28e824fSDouglas Anderson  * @dev: Device that requests the nvmem cell.
1941a28e824fSDouglas Anderson  * @cell_id: Name of nvmem cell to read.
1942a28e824fSDouglas Anderson  * @val: pointer to output value.
1943a28e824fSDouglas Anderson  *
1944a28e824fSDouglas Anderson  * Return: 0 on success or negative errno.
1945a28e824fSDouglas Anderson  */
nvmem_cell_read_variable_le_u32(struct device * dev,const char * cell_id,u32 * val)1946a28e824fSDouglas Anderson int nvmem_cell_read_variable_le_u32(struct device *dev, const char *cell_id,
1947a28e824fSDouglas Anderson 				    u32 *val)
1948a28e824fSDouglas Anderson {
1949a28e824fSDouglas Anderson 	size_t len;
19501f7b4d87SDouglas Anderson 	const u8 *buf;
1951a28e824fSDouglas Anderson 	int i;
1952a28e824fSDouglas Anderson 
1953a28e824fSDouglas Anderson 	buf = nvmem_cell_read_variable_common(dev, cell_id, sizeof(*val), &len);
1954a28e824fSDouglas Anderson 	if (IS_ERR(buf))
1955a28e824fSDouglas Anderson 		return PTR_ERR(buf);
1956a28e824fSDouglas Anderson 
1957a28e824fSDouglas Anderson 	/* Copy w/ implicit endian conversion */
1958a28e824fSDouglas Anderson 	*val = 0;
1959a28e824fSDouglas Anderson 	for (i = 0; i < len; i++)
1960a28e824fSDouglas Anderson 		*val |= buf[i] << (8 * i);
1961a28e824fSDouglas Anderson 
1962a28e824fSDouglas Anderson 	kfree(buf);
1963a28e824fSDouglas Anderson 
1964a28e824fSDouglas Anderson 	return 0;
1965a28e824fSDouglas Anderson }
1966a28e824fSDouglas Anderson EXPORT_SYMBOL_GPL(nvmem_cell_read_variable_le_u32);
1967a28e824fSDouglas Anderson 
1968a28e824fSDouglas Anderson /**
1969a28e824fSDouglas Anderson  * nvmem_cell_read_variable_le_u64() - Read up to 64-bits of data as a little endian number.
1970a28e824fSDouglas Anderson  *
1971a28e824fSDouglas Anderson  * @dev: Device that requests the nvmem cell.
1972a28e824fSDouglas Anderson  * @cell_id: Name of nvmem cell to read.
1973a28e824fSDouglas Anderson  * @val: pointer to output value.
1974a28e824fSDouglas Anderson  *
1975a28e824fSDouglas Anderson  * Return: 0 on success or negative errno.
1976a28e824fSDouglas Anderson  */
nvmem_cell_read_variable_le_u64(struct device * dev,const char * cell_id,u64 * val)1977a28e824fSDouglas Anderson int nvmem_cell_read_variable_le_u64(struct device *dev, const char *cell_id,
1978a28e824fSDouglas Anderson 				    u64 *val)
1979a28e824fSDouglas Anderson {
1980a28e824fSDouglas Anderson 	size_t len;
19811f7b4d87SDouglas Anderson 	const u8 *buf;
1982a28e824fSDouglas Anderson 	int i;
1983a28e824fSDouglas Anderson 
1984a28e824fSDouglas Anderson 	buf = nvmem_cell_read_variable_common(dev, cell_id, sizeof(*val), &len);
1985a28e824fSDouglas Anderson 	if (IS_ERR(buf))
1986a28e824fSDouglas Anderson 		return PTR_ERR(buf);
1987a28e824fSDouglas Anderson 
1988a28e824fSDouglas Anderson 	/* Copy w/ implicit endian conversion */
1989a28e824fSDouglas Anderson 	*val = 0;
1990a28e824fSDouglas Anderson 	for (i = 0; i < len; i++)
199155022fdeSColin Ian King 		*val |= (uint64_t)buf[i] << (8 * i);
1992a28e824fSDouglas Anderson 
1993a28e824fSDouglas Anderson 	kfree(buf);
1994a28e824fSDouglas Anderson 
1995a28e824fSDouglas Anderson 	return 0;
1996a28e824fSDouglas Anderson }
1997a28e824fSDouglas Anderson EXPORT_SYMBOL_GPL(nvmem_cell_read_variable_le_u64);
1998a28e824fSDouglas Anderson 
19998b977c54SYangtao Li /**
2000e2a5402eSSrinivas Kandagatla  * nvmem_device_cell_read() - Read a given nvmem device and cell
2001e2a5402eSSrinivas Kandagatla  *
2002e2a5402eSSrinivas Kandagatla  * @nvmem: nvmem device to read from.
2003e2a5402eSSrinivas Kandagatla  * @info: nvmem cell info to be read.
2004e2a5402eSSrinivas Kandagatla  * @buf: buffer pointer which will be populated on successful read.
2005e2a5402eSSrinivas Kandagatla  *
2006e2a5402eSSrinivas Kandagatla  * Return: length of successful bytes read on success and negative
2007e2a5402eSSrinivas Kandagatla  * error code on error.
2008e2a5402eSSrinivas Kandagatla  */
nvmem_device_cell_read(struct nvmem_device * nvmem,struct nvmem_cell_info * info,void * buf)2009e2a5402eSSrinivas Kandagatla ssize_t nvmem_device_cell_read(struct nvmem_device *nvmem,
2010e2a5402eSSrinivas Kandagatla 			   struct nvmem_cell_info *info, void *buf)
2011e2a5402eSSrinivas Kandagatla {
20127ae6478bSSrinivas Kandagatla 	struct nvmem_cell_entry cell;
2013e2a5402eSSrinivas Kandagatla 	int rc;
2014e2a5402eSSrinivas Kandagatla 	ssize_t len;
2015e2a5402eSSrinivas Kandagatla 
2016795ddd18SSrinivas Kandagatla 	if (!nvmem)
2017e2a5402eSSrinivas Kandagatla 		return -EINVAL;
2018e2a5402eSSrinivas Kandagatla 
20197ae6478bSSrinivas Kandagatla 	rc = nvmem_cell_info_to_nvmem_cell_entry_nodup(nvmem, info, &cell);
2020287980e4SArnd Bergmann 	if (rc)
2021e2a5402eSSrinivas Kandagatla 		return rc;
2022e2a5402eSSrinivas Kandagatla 
20235d8e6e6cSMichael Walle 	rc = __nvmem_cell_read(nvmem, &cell, buf, &len, NULL, 0);
2024287980e4SArnd Bergmann 	if (rc)
2025e2a5402eSSrinivas Kandagatla 		return rc;
2026e2a5402eSSrinivas Kandagatla 
2027e2a5402eSSrinivas Kandagatla 	return len;
2028e2a5402eSSrinivas Kandagatla }
2029e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_cell_read);
2030e2a5402eSSrinivas Kandagatla 
2031e2a5402eSSrinivas Kandagatla /**
2032e2a5402eSSrinivas Kandagatla  * nvmem_device_cell_write() - Write cell to a given nvmem device
2033e2a5402eSSrinivas Kandagatla  *
2034e2a5402eSSrinivas Kandagatla  * @nvmem: nvmem device to be written to.
203529143268SVivek Gautam  * @info: nvmem cell info to be written.
2036e2a5402eSSrinivas Kandagatla  * @buf: buffer to be written to cell.
2037e2a5402eSSrinivas Kandagatla  *
2038e2a5402eSSrinivas Kandagatla  * Return: length of bytes written or negative error code on failure.
203948f63a2cSBartosz Golaszewski  */
nvmem_device_cell_write(struct nvmem_device * nvmem,struct nvmem_cell_info * info,void * buf)2040e2a5402eSSrinivas Kandagatla int nvmem_device_cell_write(struct nvmem_device *nvmem,
2041e2a5402eSSrinivas Kandagatla 			    struct nvmem_cell_info *info, void *buf)
2042e2a5402eSSrinivas Kandagatla {
20437ae6478bSSrinivas Kandagatla 	struct nvmem_cell_entry cell;
2044e2a5402eSSrinivas Kandagatla 	int rc;
2045e2a5402eSSrinivas Kandagatla 
2046795ddd18SSrinivas Kandagatla 	if (!nvmem)
2047e2a5402eSSrinivas Kandagatla 		return -EINVAL;
2048e2a5402eSSrinivas Kandagatla 
20497ae6478bSSrinivas Kandagatla 	rc = nvmem_cell_info_to_nvmem_cell_entry_nodup(nvmem, info, &cell);
2050287980e4SArnd Bergmann 	if (rc)
2051e2a5402eSSrinivas Kandagatla 		return rc;
2052e2a5402eSSrinivas Kandagatla 
20537ae6478bSSrinivas Kandagatla 	return __nvmem_cell_entry_write(&cell, buf, cell.bytes);
2054e2a5402eSSrinivas Kandagatla }
2055e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_cell_write);
2056e2a5402eSSrinivas Kandagatla 
2057e2a5402eSSrinivas Kandagatla /**
2058e2a5402eSSrinivas Kandagatla  * nvmem_device_read() - Read from a given nvmem device
2059e2a5402eSSrinivas Kandagatla  *
2060e2a5402eSSrinivas Kandagatla  * @nvmem: nvmem device to read from.
2061e2a5402eSSrinivas Kandagatla  * @offset: offset in nvmem device.
2062e2a5402eSSrinivas Kandagatla  * @bytes: number of bytes to read.
2063e2a5402eSSrinivas Kandagatla  * @buf: buffer pointer which will be populated on successful read.
2064e2a5402eSSrinivas Kandagatla  *
2065e2a5402eSSrinivas Kandagatla  * Return: length of successful bytes read on success and negative
2066e2a5402eSSrinivas Kandagatla  * error code on error.
2067e2a5402eSSrinivas Kandagatla  */
nvmem_device_read(struct nvmem_device * nvmem,unsigned int offset,size_t bytes,void * buf)2068e2a5402eSSrinivas Kandagatla int nvmem_device_read(struct nvmem_device *nvmem,
2069e2a5402eSSrinivas Kandagatla 		      unsigned int offset,
2070e2a5402eSSrinivas Kandagatla 		      size_t bytes, void *buf)
2071e2a5402eSSrinivas Kandagatla {
2072e2a5402eSSrinivas Kandagatla 	int rc;
2073e2a5402eSSrinivas Kandagatla 
2074795ddd18SSrinivas Kandagatla 	if (!nvmem)
2075e2a5402eSSrinivas Kandagatla 		return -EINVAL;
2076e2a5402eSSrinivas Kandagatla 
2077795ddd18SSrinivas Kandagatla 	rc = nvmem_reg_read(nvmem, offset, buf, bytes);
2078e2a5402eSSrinivas Kandagatla 
2079287980e4SArnd Bergmann 	if (rc)
2080e2a5402eSSrinivas Kandagatla 		return rc;
2081e2a5402eSSrinivas Kandagatla 
2082e2a5402eSSrinivas Kandagatla 	return bytes;
2083e2a5402eSSrinivas Kandagatla }
2084e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_read);
2085e2a5402eSSrinivas Kandagatla 
2086e2a5402eSSrinivas Kandagatla /**
2087e2a5402eSSrinivas Kandagatla  * nvmem_device_write() - Write cell to a given nvmem device
2088e2a5402eSSrinivas Kandagatla  *
2089e2a5402eSSrinivas Kandagatla  * @nvmem: nvmem device to be written to.
2090e2a5402eSSrinivas Kandagatla  * @offset: offset in nvmem device.
2091e2a5402eSSrinivas Kandagatla  * @bytes: number of bytes to write.
2092e2a5402eSSrinivas Kandagatla  * @buf: buffer to be written.
2093e2a5402eSSrinivas Kandagatla  *
2094e2a5402eSSrinivas Kandagatla  * Return: length of bytes written or negative error code on failure.
209548f63a2cSBartosz Golaszewski  */
nvmem_device_write(struct nvmem_device * nvmem,unsigned int offset,size_t bytes,void * buf)2096e2a5402eSSrinivas Kandagatla int nvmem_device_write(struct nvmem_device *nvmem,
2097e2a5402eSSrinivas Kandagatla 		       unsigned int offset,
2098e2a5402eSSrinivas Kandagatla 		       size_t bytes, void *buf)
2099e2a5402eSSrinivas Kandagatla {
2100e2a5402eSSrinivas Kandagatla 	int rc;
2101e2a5402eSSrinivas Kandagatla 
2102795ddd18SSrinivas Kandagatla 	if (!nvmem)
2103e2a5402eSSrinivas Kandagatla 		return -EINVAL;
2104e2a5402eSSrinivas Kandagatla 
2105795ddd18SSrinivas Kandagatla 	rc = nvmem_reg_write(nvmem, offset, buf, bytes);
2106e2a5402eSSrinivas Kandagatla 
2107287980e4SArnd Bergmann 	if (rc)
2108e2a5402eSSrinivas Kandagatla 		return rc;
2109e2a5402eSSrinivas Kandagatla 
2110e2a5402eSSrinivas Kandagatla 
2111e2a5402eSSrinivas Kandagatla 	return bytes;
2112e2a5402eSSrinivas Kandagatla }
2113e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_write);
2114e2a5402eSSrinivas Kandagatla 
2115d7b9fd16SBartosz Golaszewski /**
2116b985f4cbSBartosz Golaszewski  * nvmem_add_cell_table() - register a table of cell info entries
2117b985f4cbSBartosz Golaszewski  *
2118b985f4cbSBartosz Golaszewski  * @table: table of cell info entries
2119b985f4cbSBartosz Golaszewski  */
nvmem_add_cell_table(struct nvmem_cell_table * table)2120b985f4cbSBartosz Golaszewski void nvmem_add_cell_table(struct nvmem_cell_table *table)
2121b985f4cbSBartosz Golaszewski {
2122b985f4cbSBartosz Golaszewski 	mutex_lock(&nvmem_cell_mutex);
2123b985f4cbSBartosz Golaszewski 	list_add_tail(&table->node, &nvmem_cell_tables);
2124b985f4cbSBartosz Golaszewski 	mutex_unlock(&nvmem_cell_mutex);
2125b985f4cbSBartosz Golaszewski }
2126b985f4cbSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_add_cell_table);
2127b985f4cbSBartosz Golaszewski 
2128b985f4cbSBartosz Golaszewski /**
2129b985f4cbSBartosz Golaszewski  * nvmem_del_cell_table() - remove a previously registered cell info table
2130b985f4cbSBartosz Golaszewski  *
2131b985f4cbSBartosz Golaszewski  * @table: table of cell info entries
2132b985f4cbSBartosz Golaszewski  */
nvmem_del_cell_table(struct nvmem_cell_table * table)2133b985f4cbSBartosz Golaszewski void nvmem_del_cell_table(struct nvmem_cell_table *table)
2134b985f4cbSBartosz Golaszewski {
2135b985f4cbSBartosz Golaszewski 	mutex_lock(&nvmem_cell_mutex);
2136b985f4cbSBartosz Golaszewski 	list_del(&table->node);
2137b985f4cbSBartosz Golaszewski 	mutex_unlock(&nvmem_cell_mutex);
2138b985f4cbSBartosz Golaszewski }
2139b985f4cbSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_del_cell_table);
2140b985f4cbSBartosz Golaszewski 
2141b985f4cbSBartosz Golaszewski /**
2142506157beSBartosz Golaszewski  * nvmem_add_cell_lookups() - register a list of cell lookup entries
2143506157beSBartosz Golaszewski  *
2144506157beSBartosz Golaszewski  * @entries: array of cell lookup entries
2145506157beSBartosz Golaszewski  * @nentries: number of cell lookup entries in the array
2146506157beSBartosz Golaszewski  */
nvmem_add_cell_lookups(struct nvmem_cell_lookup * entries,size_t nentries)2147506157beSBartosz Golaszewski void nvmem_add_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries)
2148506157beSBartosz Golaszewski {
2149506157beSBartosz Golaszewski 	int i;
2150506157beSBartosz Golaszewski 
2151506157beSBartosz Golaszewski 	mutex_lock(&nvmem_lookup_mutex);
2152506157beSBartosz Golaszewski 	for (i = 0; i < nentries; i++)
2153506157beSBartosz Golaszewski 		list_add_tail(&entries[i].node, &nvmem_lookup_list);
2154506157beSBartosz Golaszewski 	mutex_unlock(&nvmem_lookup_mutex);
2155506157beSBartosz Golaszewski }
2156506157beSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_add_cell_lookups);
2157506157beSBartosz Golaszewski 
2158506157beSBartosz Golaszewski /**
2159506157beSBartosz Golaszewski  * nvmem_del_cell_lookups() - remove a list of previously added cell lookup
2160506157beSBartosz Golaszewski  *                            entries
2161506157beSBartosz Golaszewski  *
2162506157beSBartosz Golaszewski  * @entries: array of cell lookup entries
2163506157beSBartosz Golaszewski  * @nentries: number of cell lookup entries in the array
2164506157beSBartosz Golaszewski  */
nvmem_del_cell_lookups(struct nvmem_cell_lookup * entries,size_t nentries)2165506157beSBartosz Golaszewski void nvmem_del_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries)
2166506157beSBartosz Golaszewski {
2167506157beSBartosz Golaszewski 	int i;
2168506157beSBartosz Golaszewski 
2169506157beSBartosz Golaszewski 	mutex_lock(&nvmem_lookup_mutex);
2170506157beSBartosz Golaszewski 	for (i = 0; i < nentries; i++)
2171506157beSBartosz Golaszewski 		list_del(&entries[i].node);
2172506157beSBartosz Golaszewski 	mutex_unlock(&nvmem_lookup_mutex);
2173506157beSBartosz Golaszewski }
2174506157beSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_del_cell_lookups);
2175506157beSBartosz Golaszewski 
2176506157beSBartosz Golaszewski /**
2177d7b9fd16SBartosz Golaszewski  * nvmem_dev_name() - Get the name of a given nvmem device.
2178d7b9fd16SBartosz Golaszewski  *
2179d7b9fd16SBartosz Golaszewski  * @nvmem: nvmem device.
2180d7b9fd16SBartosz Golaszewski  *
2181d7b9fd16SBartosz Golaszewski  * Return: name of the nvmem device.
2182d7b9fd16SBartosz Golaszewski  */
nvmem_dev_name(struct nvmem_device * nvmem)2183d7b9fd16SBartosz Golaszewski const char *nvmem_dev_name(struct nvmem_device *nvmem)
2184d7b9fd16SBartosz Golaszewski {
2185d7b9fd16SBartosz Golaszewski 	return dev_name(&nvmem->dev);
2186d7b9fd16SBartosz Golaszewski }
2187d7b9fd16SBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_dev_name);
2188d7b9fd16SBartosz Golaszewski 
218933cf42e6SRafał Miłecki /**
219033cf42e6SRafał Miłecki  * nvmem_dev_size() - Get the size of a given nvmem device.
219133cf42e6SRafał Miłecki  *
219233cf42e6SRafał Miłecki  * @nvmem: nvmem device.
219333cf42e6SRafał Miłecki  *
219433cf42e6SRafał Miłecki  * Return: size of the nvmem device.
219533cf42e6SRafał Miłecki  */
nvmem_dev_size(struct nvmem_device * nvmem)219633cf42e6SRafał Miłecki size_t nvmem_dev_size(struct nvmem_device *nvmem)
219733cf42e6SRafał Miłecki {
219833cf42e6SRafał Miłecki 	return nvmem->size;
219933cf42e6SRafał Miłecki }
220033cf42e6SRafał Miłecki EXPORT_SYMBOL_GPL(nvmem_dev_size);
220133cf42e6SRafał Miłecki 
nvmem_init(void)2202eace75cfSSrinivas Kandagatla static int __init nvmem_init(void)
2203eace75cfSSrinivas Kandagatla {
2204fc29fd82SMiquel Raynal 	int ret;
2205fc29fd82SMiquel Raynal 
2206fc29fd82SMiquel Raynal 	ret = bus_register(&nvmem_bus_type);
2207fc29fd82SMiquel Raynal 	if (ret)
2208fc29fd82SMiquel Raynal 		return ret;
2209fc29fd82SMiquel Raynal 
2210fc29fd82SMiquel Raynal 	ret = nvmem_layout_bus_register();
2211fc29fd82SMiquel Raynal 	if (ret)
2212fc29fd82SMiquel Raynal 		bus_unregister(&nvmem_bus_type);
2213fc29fd82SMiquel Raynal 
2214fc29fd82SMiquel Raynal 	return ret;
2215eace75cfSSrinivas Kandagatla }
2216eace75cfSSrinivas Kandagatla 
nvmem_exit(void)2217eace75cfSSrinivas Kandagatla static void __exit nvmem_exit(void)
2218eace75cfSSrinivas Kandagatla {
2219fc29fd82SMiquel Raynal 	nvmem_layout_bus_unregister();
2220eace75cfSSrinivas Kandagatla 	bus_unregister(&nvmem_bus_type);
2221eace75cfSSrinivas Kandagatla }
2222eace75cfSSrinivas Kandagatla 
2223eace75cfSSrinivas Kandagatla subsys_initcall(nvmem_init);
2224eace75cfSSrinivas Kandagatla module_exit(nvmem_exit);
2225eace75cfSSrinivas Kandagatla 
2226eace75cfSSrinivas Kandagatla MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org");
2227eace75cfSSrinivas Kandagatla MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com");
2228eace75cfSSrinivas Kandagatla MODULE_DESCRIPTION("nvmem Driver Core");
2229