xref: /linux/drivers/nvmem/core.c (revision 4f6b838c378a52ea3ae0b15f12ca8a20849072fa)
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 
2284400305SSrinivas Kandagatla struct nvmem_device {
2384400305SSrinivas Kandagatla 	struct module		*owner;
2484400305SSrinivas Kandagatla 	struct device		dev;
2584400305SSrinivas Kandagatla 	int			stride;
2684400305SSrinivas Kandagatla 	int			word_size;
2784400305SSrinivas Kandagatla 	int			id;
2884400305SSrinivas Kandagatla 	struct kref		refcnt;
2984400305SSrinivas Kandagatla 	size_t			size;
3084400305SSrinivas Kandagatla 	bool			read_only;
3184400305SSrinivas Kandagatla 	bool			root_only;
3284400305SSrinivas Kandagatla 	int			flags;
3384400305SSrinivas Kandagatla 	enum nvmem_type		type;
3484400305SSrinivas Kandagatla 	struct bin_attribute	eeprom;
3584400305SSrinivas Kandagatla 	struct device		*base_dev;
3684400305SSrinivas Kandagatla 	struct list_head	cells;
3784400305SSrinivas Kandagatla 	nvmem_reg_read_t	reg_read;
3884400305SSrinivas Kandagatla 	nvmem_reg_write_t	reg_write;
3984400305SSrinivas Kandagatla 	struct gpio_desc	*wp_gpio;
4084400305SSrinivas Kandagatla 	void *priv;
4184400305SSrinivas Kandagatla };
4284400305SSrinivas Kandagatla 
4384400305SSrinivas Kandagatla #define to_nvmem_device(d) container_of(d, struct nvmem_device, dev)
4484400305SSrinivas Kandagatla 
4584400305SSrinivas Kandagatla #define FLAG_COMPAT		BIT(0)
46b6c217abSAndrew Lunn 
47eace75cfSSrinivas Kandagatla struct nvmem_cell {
48eace75cfSSrinivas Kandagatla 	const char		*name;
49eace75cfSSrinivas Kandagatla 	int			offset;
50eace75cfSSrinivas Kandagatla 	int			bytes;
51eace75cfSSrinivas Kandagatla 	int			bit_offset;
52eace75cfSSrinivas Kandagatla 	int			nbits;
530749aa25SSrinivas Kandagatla 	struct device_node	*np;
54eace75cfSSrinivas Kandagatla 	struct nvmem_device	*nvmem;
55eace75cfSSrinivas Kandagatla 	struct list_head	node;
56eace75cfSSrinivas Kandagatla };
57eace75cfSSrinivas Kandagatla 
58eace75cfSSrinivas Kandagatla static DEFINE_MUTEX(nvmem_mutex);
59eace75cfSSrinivas Kandagatla static DEFINE_IDA(nvmem_ida);
60eace75cfSSrinivas Kandagatla 
61b985f4cbSBartosz Golaszewski static DEFINE_MUTEX(nvmem_cell_mutex);
62b985f4cbSBartosz Golaszewski static LIST_HEAD(nvmem_cell_tables);
63b985f4cbSBartosz Golaszewski 
64506157beSBartosz Golaszewski static DEFINE_MUTEX(nvmem_lookup_mutex);
65506157beSBartosz Golaszewski static LIST_HEAD(nvmem_lookup_list);
66506157beSBartosz Golaszewski 
67bee1138bSBartosz Golaszewski static BLOCKING_NOTIFIER_HEAD(nvmem_notifier);
68bee1138bSBartosz Golaszewski 
69b96fc541SMichael Auchter static int nvmem_reg_read(struct nvmem_device *nvmem, unsigned int offset,
70b96fc541SMichael Auchter 			  void *val, size_t bytes)
71b96fc541SMichael Auchter {
72b96fc541SMichael Auchter 	if (nvmem->reg_read)
73b96fc541SMichael Auchter 		return nvmem->reg_read(nvmem->priv, offset, val, bytes);
74b96fc541SMichael Auchter 
75b96fc541SMichael Auchter 	return -EINVAL;
76b96fc541SMichael Auchter }
77b96fc541SMichael Auchter 
78b96fc541SMichael Auchter static int nvmem_reg_write(struct nvmem_device *nvmem, unsigned int offset,
79b96fc541SMichael Auchter 			   void *val, size_t bytes)
80b96fc541SMichael Auchter {
81b96fc541SMichael Auchter 	int ret;
82b96fc541SMichael Auchter 
83b96fc541SMichael Auchter 	if (nvmem->reg_write) {
84b96fc541SMichael Auchter 		gpiod_set_value_cansleep(nvmem->wp_gpio, 0);
85b96fc541SMichael Auchter 		ret = nvmem->reg_write(nvmem->priv, offset, val, bytes);
86b96fc541SMichael Auchter 		gpiod_set_value_cansleep(nvmem->wp_gpio, 1);
87b96fc541SMichael Auchter 		return ret;
88b96fc541SMichael Auchter 	}
89b96fc541SMichael Auchter 
90b96fc541SMichael Auchter 	return -EINVAL;
91b96fc541SMichael Auchter }
92b96fc541SMichael Auchter 
9384400305SSrinivas Kandagatla #ifdef CONFIG_NVMEM_SYSFS
9484400305SSrinivas Kandagatla static const char * const nvmem_type_str[] = {
9584400305SSrinivas Kandagatla 	[NVMEM_TYPE_UNKNOWN] = "Unknown",
9684400305SSrinivas Kandagatla 	[NVMEM_TYPE_EEPROM] = "EEPROM",
9784400305SSrinivas Kandagatla 	[NVMEM_TYPE_OTP] = "OTP",
9884400305SSrinivas Kandagatla 	[NVMEM_TYPE_BATTERY_BACKED] = "Battery backed",
9984400305SSrinivas Kandagatla };
10084400305SSrinivas Kandagatla 
10184400305SSrinivas Kandagatla #ifdef CONFIG_DEBUG_LOCK_ALLOC
10284400305SSrinivas Kandagatla static struct lock_class_key eeprom_lock_key;
10384400305SSrinivas Kandagatla #endif
10484400305SSrinivas Kandagatla 
10584400305SSrinivas Kandagatla static ssize_t type_show(struct device *dev,
10684400305SSrinivas Kandagatla 			 struct device_attribute *attr, char *buf)
10784400305SSrinivas Kandagatla {
10884400305SSrinivas Kandagatla 	struct nvmem_device *nvmem = to_nvmem_device(dev);
10984400305SSrinivas Kandagatla 
11084400305SSrinivas Kandagatla 	return sprintf(buf, "%s\n", nvmem_type_str[nvmem->type]);
11184400305SSrinivas Kandagatla }
11284400305SSrinivas Kandagatla 
11384400305SSrinivas Kandagatla static DEVICE_ATTR_RO(type);
11484400305SSrinivas Kandagatla 
11584400305SSrinivas Kandagatla static struct attribute *nvmem_attrs[] = {
11684400305SSrinivas Kandagatla 	&dev_attr_type.attr,
11784400305SSrinivas Kandagatla 	NULL,
11884400305SSrinivas Kandagatla };
11984400305SSrinivas Kandagatla 
12084400305SSrinivas Kandagatla static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj,
12184400305SSrinivas Kandagatla 				   struct bin_attribute *attr, char *buf,
12284400305SSrinivas Kandagatla 				   loff_t pos, size_t count)
12384400305SSrinivas Kandagatla {
12484400305SSrinivas Kandagatla 	struct device *dev;
12584400305SSrinivas Kandagatla 	struct nvmem_device *nvmem;
12684400305SSrinivas Kandagatla 	int rc;
12784400305SSrinivas Kandagatla 
12884400305SSrinivas Kandagatla 	if (attr->private)
12984400305SSrinivas Kandagatla 		dev = attr->private;
13084400305SSrinivas Kandagatla 	else
13128371cc6STian Tao 		dev = kobj_to_dev(kobj);
13284400305SSrinivas Kandagatla 	nvmem = to_nvmem_device(dev);
13384400305SSrinivas Kandagatla 
13484400305SSrinivas Kandagatla 	/* Stop the user from reading */
13584400305SSrinivas Kandagatla 	if (pos >= nvmem->size)
13684400305SSrinivas Kandagatla 		return 0;
13784400305SSrinivas Kandagatla 
13883566715SDouglas Anderson 	if (!IS_ALIGNED(pos, nvmem->stride))
13983566715SDouglas Anderson 		return -EINVAL;
14083566715SDouglas Anderson 
14184400305SSrinivas Kandagatla 	if (count < nvmem->word_size)
14284400305SSrinivas Kandagatla 		return -EINVAL;
14384400305SSrinivas Kandagatla 
14484400305SSrinivas Kandagatla 	if (pos + count > nvmem->size)
14584400305SSrinivas Kandagatla 		count = nvmem->size - pos;
14684400305SSrinivas Kandagatla 
14784400305SSrinivas Kandagatla 	count = round_down(count, nvmem->word_size);
14884400305SSrinivas Kandagatla 
14984400305SSrinivas Kandagatla 	if (!nvmem->reg_read)
15084400305SSrinivas Kandagatla 		return -EPERM;
15184400305SSrinivas Kandagatla 
152b96fc541SMichael Auchter 	rc = nvmem_reg_read(nvmem, pos, buf, count);
15384400305SSrinivas Kandagatla 
15484400305SSrinivas Kandagatla 	if (rc)
15584400305SSrinivas Kandagatla 		return rc;
15684400305SSrinivas Kandagatla 
15784400305SSrinivas Kandagatla 	return count;
15884400305SSrinivas Kandagatla }
15984400305SSrinivas Kandagatla 
16084400305SSrinivas Kandagatla static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj,
16184400305SSrinivas Kandagatla 				    struct bin_attribute *attr, char *buf,
16284400305SSrinivas Kandagatla 				    loff_t pos, size_t count)
16384400305SSrinivas Kandagatla {
16484400305SSrinivas Kandagatla 	struct device *dev;
16584400305SSrinivas Kandagatla 	struct nvmem_device *nvmem;
16684400305SSrinivas Kandagatla 	int rc;
16784400305SSrinivas Kandagatla 
16884400305SSrinivas Kandagatla 	if (attr->private)
16984400305SSrinivas Kandagatla 		dev = attr->private;
17084400305SSrinivas Kandagatla 	else
17128371cc6STian Tao 		dev = kobj_to_dev(kobj);
17284400305SSrinivas Kandagatla 	nvmem = to_nvmem_device(dev);
17384400305SSrinivas Kandagatla 
17484400305SSrinivas Kandagatla 	/* Stop the user from writing */
17584400305SSrinivas Kandagatla 	if (pos >= nvmem->size)
17684400305SSrinivas Kandagatla 		return -EFBIG;
17784400305SSrinivas Kandagatla 
17883566715SDouglas Anderson 	if (!IS_ALIGNED(pos, nvmem->stride))
17983566715SDouglas Anderson 		return -EINVAL;
18083566715SDouglas Anderson 
18184400305SSrinivas Kandagatla 	if (count < nvmem->word_size)
18284400305SSrinivas Kandagatla 		return -EINVAL;
18384400305SSrinivas Kandagatla 
18484400305SSrinivas Kandagatla 	if (pos + count > nvmem->size)
18584400305SSrinivas Kandagatla 		count = nvmem->size - pos;
18684400305SSrinivas Kandagatla 
18784400305SSrinivas Kandagatla 	count = round_down(count, nvmem->word_size);
18884400305SSrinivas Kandagatla 
18984400305SSrinivas Kandagatla 	if (!nvmem->reg_write)
19084400305SSrinivas Kandagatla 		return -EPERM;
19184400305SSrinivas Kandagatla 
192b96fc541SMichael Auchter 	rc = nvmem_reg_write(nvmem, pos, buf, count);
19384400305SSrinivas Kandagatla 
19484400305SSrinivas Kandagatla 	if (rc)
19584400305SSrinivas Kandagatla 		return rc;
19684400305SSrinivas Kandagatla 
19784400305SSrinivas Kandagatla 	return count;
19884400305SSrinivas Kandagatla }
19984400305SSrinivas Kandagatla 
2002a4542e5SSrinivas Kandagatla static umode_t nvmem_bin_attr_get_umode(struct nvmem_device *nvmem)
20184400305SSrinivas Kandagatla {
20284400305SSrinivas Kandagatla 	umode_t mode = 0400;
20384400305SSrinivas Kandagatla 
20484400305SSrinivas Kandagatla 	if (!nvmem->root_only)
20584400305SSrinivas Kandagatla 		mode |= 0044;
20684400305SSrinivas Kandagatla 
20784400305SSrinivas Kandagatla 	if (!nvmem->read_only)
20884400305SSrinivas Kandagatla 		mode |= 0200;
20984400305SSrinivas Kandagatla 
21084400305SSrinivas Kandagatla 	if (!nvmem->reg_write)
21184400305SSrinivas Kandagatla 		mode &= ~0200;
21284400305SSrinivas Kandagatla 
21384400305SSrinivas Kandagatla 	if (!nvmem->reg_read)
21484400305SSrinivas Kandagatla 		mode &= ~0444;
21584400305SSrinivas Kandagatla 
21684400305SSrinivas Kandagatla 	return mode;
21784400305SSrinivas Kandagatla }
21884400305SSrinivas Kandagatla 
2192a4542e5SSrinivas Kandagatla static umode_t nvmem_bin_attr_is_visible(struct kobject *kobj,
2202a4542e5SSrinivas Kandagatla 					 struct bin_attribute *attr, int i)
2212a4542e5SSrinivas Kandagatla {
22228371cc6STian Tao 	struct device *dev = kobj_to_dev(kobj);
2232a4542e5SSrinivas Kandagatla 	struct nvmem_device *nvmem = to_nvmem_device(dev);
2242a4542e5SSrinivas Kandagatla 
2252a4542e5SSrinivas Kandagatla 	return nvmem_bin_attr_get_umode(nvmem);
2262a4542e5SSrinivas Kandagatla }
2272a4542e5SSrinivas Kandagatla 
22884400305SSrinivas Kandagatla /* default read/write permissions */
22984400305SSrinivas Kandagatla static struct bin_attribute bin_attr_rw_nvmem = {
23084400305SSrinivas Kandagatla 	.attr	= {
23184400305SSrinivas Kandagatla 		.name	= "nvmem",
23284400305SSrinivas Kandagatla 		.mode	= 0644,
23384400305SSrinivas Kandagatla 	},
23484400305SSrinivas Kandagatla 	.read	= bin_attr_nvmem_read,
23584400305SSrinivas Kandagatla 	.write	= bin_attr_nvmem_write,
23684400305SSrinivas Kandagatla };
23784400305SSrinivas Kandagatla 
23884400305SSrinivas Kandagatla static struct bin_attribute *nvmem_bin_attributes[] = {
23984400305SSrinivas Kandagatla 	&bin_attr_rw_nvmem,
24084400305SSrinivas Kandagatla 	NULL,
24184400305SSrinivas Kandagatla };
24284400305SSrinivas Kandagatla 
24384400305SSrinivas Kandagatla static const struct attribute_group nvmem_bin_group = {
24484400305SSrinivas Kandagatla 	.bin_attrs	= nvmem_bin_attributes,
24584400305SSrinivas Kandagatla 	.attrs		= nvmem_attrs,
24684400305SSrinivas Kandagatla 	.is_bin_visible = nvmem_bin_attr_is_visible,
24784400305SSrinivas Kandagatla };
24884400305SSrinivas Kandagatla 
24984400305SSrinivas Kandagatla static const struct attribute_group *nvmem_dev_groups[] = {
25084400305SSrinivas Kandagatla 	&nvmem_bin_group,
25184400305SSrinivas Kandagatla 	NULL,
25284400305SSrinivas Kandagatla };
25384400305SSrinivas Kandagatla 
2542a4542e5SSrinivas Kandagatla static struct bin_attribute bin_attr_nvmem_eeprom_compat = {
25584400305SSrinivas Kandagatla 	.attr	= {
2562a4542e5SSrinivas Kandagatla 		.name	= "eeprom",
25784400305SSrinivas Kandagatla 	},
25884400305SSrinivas Kandagatla 	.read	= bin_attr_nvmem_read,
25984400305SSrinivas Kandagatla 	.write	= bin_attr_nvmem_write,
26084400305SSrinivas Kandagatla };
26184400305SSrinivas Kandagatla 
26284400305SSrinivas Kandagatla /*
26384400305SSrinivas Kandagatla  * nvmem_setup_compat() - Create an additional binary entry in
26484400305SSrinivas Kandagatla  * drivers sys directory, to be backwards compatible with the older
26584400305SSrinivas Kandagatla  * drivers/misc/eeprom drivers.
26684400305SSrinivas Kandagatla  */
26784400305SSrinivas Kandagatla static int nvmem_sysfs_setup_compat(struct nvmem_device *nvmem,
26884400305SSrinivas Kandagatla 				    const struct nvmem_config *config)
26984400305SSrinivas Kandagatla {
27084400305SSrinivas Kandagatla 	int rval;
27184400305SSrinivas Kandagatla 
27284400305SSrinivas Kandagatla 	if (!config->compat)
27384400305SSrinivas Kandagatla 		return 0;
27484400305SSrinivas Kandagatla 
27584400305SSrinivas Kandagatla 	if (!config->base_dev)
27684400305SSrinivas Kandagatla 		return -EINVAL;
27784400305SSrinivas Kandagatla 
2782a4542e5SSrinivas Kandagatla 	nvmem->eeprom = bin_attr_nvmem_eeprom_compat;
2792a4542e5SSrinivas Kandagatla 	nvmem->eeprom.attr.mode = nvmem_bin_attr_get_umode(nvmem);
28084400305SSrinivas Kandagatla 	nvmem->eeprom.size = nvmem->size;
28184400305SSrinivas Kandagatla #ifdef CONFIG_DEBUG_LOCK_ALLOC
28284400305SSrinivas Kandagatla 	nvmem->eeprom.attr.key = &eeprom_lock_key;
28384400305SSrinivas Kandagatla #endif
28484400305SSrinivas Kandagatla 	nvmem->eeprom.private = &nvmem->dev;
28584400305SSrinivas Kandagatla 	nvmem->base_dev = config->base_dev;
28684400305SSrinivas Kandagatla 
28784400305SSrinivas Kandagatla 	rval = device_create_bin_file(nvmem->base_dev, &nvmem->eeprom);
28884400305SSrinivas Kandagatla 	if (rval) {
28984400305SSrinivas Kandagatla 		dev_err(&nvmem->dev,
29084400305SSrinivas Kandagatla 			"Failed to create eeprom binary file %d\n", rval);
29184400305SSrinivas Kandagatla 		return rval;
29284400305SSrinivas Kandagatla 	}
29384400305SSrinivas Kandagatla 
29484400305SSrinivas Kandagatla 	nvmem->flags |= FLAG_COMPAT;
29584400305SSrinivas Kandagatla 
29684400305SSrinivas Kandagatla 	return 0;
29784400305SSrinivas Kandagatla }
29884400305SSrinivas Kandagatla 
29984400305SSrinivas Kandagatla static void nvmem_sysfs_remove_compat(struct nvmem_device *nvmem,
30084400305SSrinivas Kandagatla 			      const struct nvmem_config *config)
30184400305SSrinivas Kandagatla {
30284400305SSrinivas Kandagatla 	if (config->compat)
30384400305SSrinivas Kandagatla 		device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom);
30484400305SSrinivas Kandagatla }
30584400305SSrinivas Kandagatla 
30684400305SSrinivas Kandagatla #else /* CONFIG_NVMEM_SYSFS */
30784400305SSrinivas Kandagatla 
30884400305SSrinivas Kandagatla static int nvmem_sysfs_setup_compat(struct nvmem_device *nvmem,
30984400305SSrinivas Kandagatla 				    const struct nvmem_config *config)
31084400305SSrinivas Kandagatla {
31184400305SSrinivas Kandagatla 	return -ENOSYS;
31284400305SSrinivas Kandagatla }
31384400305SSrinivas Kandagatla static void nvmem_sysfs_remove_compat(struct nvmem_device *nvmem,
31484400305SSrinivas Kandagatla 				      const struct nvmem_config *config)
31584400305SSrinivas Kandagatla {
31684400305SSrinivas Kandagatla }
31784400305SSrinivas Kandagatla 
31884400305SSrinivas Kandagatla #endif /* CONFIG_NVMEM_SYSFS */
319a8b44d5dSAndy Shevchenko 
320eace75cfSSrinivas Kandagatla static void nvmem_release(struct device *dev)
321eace75cfSSrinivas Kandagatla {
322eace75cfSSrinivas Kandagatla 	struct nvmem_device *nvmem = to_nvmem_device(dev);
323eace75cfSSrinivas Kandagatla 
3241eb51d6aSBartosz Golaszewski 	ida_free(&nvmem_ida, nvmem->id);
325a9c3766cSKhouloud Touil 	gpiod_put(nvmem->wp_gpio);
326eace75cfSSrinivas Kandagatla 	kfree(nvmem);
327eace75cfSSrinivas Kandagatla }
328eace75cfSSrinivas Kandagatla 
329eace75cfSSrinivas Kandagatla static const struct device_type nvmem_provider_type = {
330eace75cfSSrinivas Kandagatla 	.release	= nvmem_release,
331eace75cfSSrinivas Kandagatla };
332eace75cfSSrinivas Kandagatla 
333eace75cfSSrinivas Kandagatla static struct bus_type nvmem_bus_type = {
334eace75cfSSrinivas Kandagatla 	.name		= "nvmem",
335eace75cfSSrinivas Kandagatla };
336eace75cfSSrinivas Kandagatla 
337eace75cfSSrinivas Kandagatla static void nvmem_cell_drop(struct nvmem_cell *cell)
338eace75cfSSrinivas Kandagatla {
339bee1138bSBartosz Golaszewski 	blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_REMOVE, cell);
340c7235ee3SBartosz Golaszewski 	mutex_lock(&nvmem_mutex);
341eace75cfSSrinivas Kandagatla 	list_del(&cell->node);
342c7235ee3SBartosz Golaszewski 	mutex_unlock(&nvmem_mutex);
3430749aa25SSrinivas Kandagatla 	of_node_put(cell->np);
34416bb7abcSBitan Biswas 	kfree_const(cell->name);
345eace75cfSSrinivas Kandagatla 	kfree(cell);
346eace75cfSSrinivas Kandagatla }
347eace75cfSSrinivas Kandagatla 
348eace75cfSSrinivas Kandagatla static void nvmem_device_remove_all_cells(const struct nvmem_device *nvmem)
349eace75cfSSrinivas Kandagatla {
3501852183eSBartosz Golaszewski 	struct nvmem_cell *cell, *p;
351eace75cfSSrinivas Kandagatla 
352c7235ee3SBartosz Golaszewski 	list_for_each_entry_safe(cell, p, &nvmem->cells, node)
353eace75cfSSrinivas Kandagatla 		nvmem_cell_drop(cell);
354eace75cfSSrinivas Kandagatla }
355eace75cfSSrinivas Kandagatla 
356eace75cfSSrinivas Kandagatla static void nvmem_cell_add(struct nvmem_cell *cell)
357eace75cfSSrinivas Kandagatla {
358c7235ee3SBartosz Golaszewski 	mutex_lock(&nvmem_mutex);
359c7235ee3SBartosz Golaszewski 	list_add_tail(&cell->node, &cell->nvmem->cells);
360c7235ee3SBartosz Golaszewski 	mutex_unlock(&nvmem_mutex);
361bee1138bSBartosz Golaszewski 	blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_ADD, cell);
362eace75cfSSrinivas Kandagatla }
363eace75cfSSrinivas Kandagatla 
364*fc9eec4dSVadym Kochan static int nvmem_cell_info_to_nvmem_cell_nodup(struct nvmem_device *nvmem,
365eace75cfSSrinivas Kandagatla 					const struct nvmem_cell_info *info,
366eace75cfSSrinivas Kandagatla 					struct nvmem_cell *cell)
367eace75cfSSrinivas Kandagatla {
368eace75cfSSrinivas Kandagatla 	cell->nvmem = nvmem;
369eace75cfSSrinivas Kandagatla 	cell->offset = info->offset;
370eace75cfSSrinivas Kandagatla 	cell->bytes = info->bytes;
371*fc9eec4dSVadym Kochan 	cell->name = info->name;
372eace75cfSSrinivas Kandagatla 
373eace75cfSSrinivas Kandagatla 	cell->bit_offset = info->bit_offset;
374eace75cfSSrinivas Kandagatla 	cell->nbits = info->nbits;
375eace75cfSSrinivas Kandagatla 
376eace75cfSSrinivas Kandagatla 	if (cell->nbits)
377eace75cfSSrinivas Kandagatla 		cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset,
378eace75cfSSrinivas Kandagatla 					   BITS_PER_BYTE);
379eace75cfSSrinivas Kandagatla 
380eace75cfSSrinivas Kandagatla 	if (!IS_ALIGNED(cell->offset, nvmem->stride)) {
381eace75cfSSrinivas Kandagatla 		dev_err(&nvmem->dev,
382eace75cfSSrinivas Kandagatla 			"cell %s unaligned to nvmem stride %d\n",
383*fc9eec4dSVadym Kochan 			cell->name ?: "<unknown>", nvmem->stride);
384eace75cfSSrinivas Kandagatla 		return -EINVAL;
385eace75cfSSrinivas Kandagatla 	}
386eace75cfSSrinivas Kandagatla 
387eace75cfSSrinivas Kandagatla 	return 0;
388eace75cfSSrinivas Kandagatla }
389eace75cfSSrinivas Kandagatla 
390*fc9eec4dSVadym Kochan static int nvmem_cell_info_to_nvmem_cell(struct nvmem_device *nvmem,
391*fc9eec4dSVadym Kochan 				const struct nvmem_cell_info *info,
392*fc9eec4dSVadym Kochan 				struct nvmem_cell *cell)
393*fc9eec4dSVadym Kochan {
394*fc9eec4dSVadym Kochan 	int err;
395*fc9eec4dSVadym Kochan 
396*fc9eec4dSVadym Kochan 	err = nvmem_cell_info_to_nvmem_cell_nodup(nvmem, info, cell);
397*fc9eec4dSVadym Kochan 	if (err)
398*fc9eec4dSVadym Kochan 		return err;
399*fc9eec4dSVadym Kochan 
400*fc9eec4dSVadym Kochan 	cell->name = kstrdup_const(info->name, GFP_KERNEL);
401*fc9eec4dSVadym Kochan 	if (!cell->name)
402*fc9eec4dSVadym Kochan 		return -ENOMEM;
403*fc9eec4dSVadym Kochan 
404*fc9eec4dSVadym Kochan 	return 0;
405*fc9eec4dSVadym Kochan }
406*fc9eec4dSVadym Kochan 
407b3db17e4SAndrew Lunn /**
408b3db17e4SAndrew Lunn  * nvmem_add_cells() - Add cell information to an nvmem device
409b3db17e4SAndrew Lunn  *
410b3db17e4SAndrew Lunn  * @nvmem: nvmem device to add cells to.
411b3db17e4SAndrew Lunn  * @info: nvmem cell info to add to the device
412b3db17e4SAndrew Lunn  * @ncells: number of cells in info
413b3db17e4SAndrew Lunn  *
414b3db17e4SAndrew Lunn  * Return: 0 or negative error code on failure.
415b3db17e4SAndrew Lunn  */
416ef92ab30SSrinivas Kandagatla static int nvmem_add_cells(struct nvmem_device *nvmem,
417b3db17e4SAndrew Lunn 		    const struct nvmem_cell_info *info,
418b3db17e4SAndrew Lunn 		    int ncells)
419eace75cfSSrinivas Kandagatla {
420eace75cfSSrinivas Kandagatla 	struct nvmem_cell **cells;
421eace75cfSSrinivas Kandagatla 	int i, rval;
422eace75cfSSrinivas Kandagatla 
423b3db17e4SAndrew Lunn 	cells = kcalloc(ncells, sizeof(*cells), GFP_KERNEL);
424eace75cfSSrinivas Kandagatla 	if (!cells)
425eace75cfSSrinivas Kandagatla 		return -ENOMEM;
426eace75cfSSrinivas Kandagatla 
427b3db17e4SAndrew Lunn 	for (i = 0; i < ncells; i++) {
428eace75cfSSrinivas Kandagatla 		cells[i] = kzalloc(sizeof(**cells), GFP_KERNEL);
429eace75cfSSrinivas Kandagatla 		if (!cells[i]) {
430eace75cfSSrinivas Kandagatla 			rval = -ENOMEM;
431eace75cfSSrinivas Kandagatla 			goto err;
432eace75cfSSrinivas Kandagatla 		}
433eace75cfSSrinivas Kandagatla 
434eace75cfSSrinivas Kandagatla 		rval = nvmem_cell_info_to_nvmem_cell(nvmem, &info[i], cells[i]);
435287980e4SArnd Bergmann 		if (rval) {
436eace75cfSSrinivas Kandagatla 			kfree(cells[i]);
437eace75cfSSrinivas Kandagatla 			goto err;
438eace75cfSSrinivas Kandagatla 		}
439eace75cfSSrinivas Kandagatla 
440eace75cfSSrinivas Kandagatla 		nvmem_cell_add(cells[i]);
441eace75cfSSrinivas Kandagatla 	}
442eace75cfSSrinivas Kandagatla 
443eace75cfSSrinivas Kandagatla 	/* remove tmp array */
444eace75cfSSrinivas Kandagatla 	kfree(cells);
445eace75cfSSrinivas Kandagatla 
446eace75cfSSrinivas Kandagatla 	return 0;
447eace75cfSSrinivas Kandagatla err:
448dfdf1414SRasmus Villemoes 	while (i--)
449eace75cfSSrinivas Kandagatla 		nvmem_cell_drop(cells[i]);
450eace75cfSSrinivas Kandagatla 
451dfdf1414SRasmus Villemoes 	kfree(cells);
452dfdf1414SRasmus Villemoes 
453eace75cfSSrinivas Kandagatla 	return rval;
454eace75cfSSrinivas Kandagatla }
455eace75cfSSrinivas Kandagatla 
456bee1138bSBartosz Golaszewski /**
457bee1138bSBartosz Golaszewski  * nvmem_register_notifier() - Register a notifier block for nvmem events.
458bee1138bSBartosz Golaszewski  *
459bee1138bSBartosz Golaszewski  * @nb: notifier block to be called on nvmem events.
460bee1138bSBartosz Golaszewski  *
461bee1138bSBartosz Golaszewski  * Return: 0 on success, negative error number on failure.
462bee1138bSBartosz Golaszewski  */
463bee1138bSBartosz Golaszewski int nvmem_register_notifier(struct notifier_block *nb)
464bee1138bSBartosz Golaszewski {
465bee1138bSBartosz Golaszewski 	return blocking_notifier_chain_register(&nvmem_notifier, nb);
466bee1138bSBartosz Golaszewski }
467bee1138bSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_register_notifier);
468bee1138bSBartosz Golaszewski 
469bee1138bSBartosz Golaszewski /**
470bee1138bSBartosz Golaszewski  * nvmem_unregister_notifier() - Unregister a notifier block for nvmem events.
471bee1138bSBartosz Golaszewski  *
472bee1138bSBartosz Golaszewski  * @nb: notifier block to be unregistered.
473bee1138bSBartosz Golaszewski  *
474bee1138bSBartosz Golaszewski  * Return: 0 on success, negative error number on failure.
475bee1138bSBartosz Golaszewski  */
476bee1138bSBartosz Golaszewski int nvmem_unregister_notifier(struct notifier_block *nb)
477bee1138bSBartosz Golaszewski {
478bee1138bSBartosz Golaszewski 	return blocking_notifier_chain_unregister(&nvmem_notifier, nb);
479bee1138bSBartosz Golaszewski }
480bee1138bSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_unregister_notifier);
481bee1138bSBartosz Golaszewski 
482b985f4cbSBartosz Golaszewski static int nvmem_add_cells_from_table(struct nvmem_device *nvmem)
483b985f4cbSBartosz Golaszewski {
484b985f4cbSBartosz Golaszewski 	const struct nvmem_cell_info *info;
485b985f4cbSBartosz Golaszewski 	struct nvmem_cell_table *table;
486b985f4cbSBartosz Golaszewski 	struct nvmem_cell *cell;
487b985f4cbSBartosz Golaszewski 	int rval = 0, i;
488b985f4cbSBartosz Golaszewski 
489b985f4cbSBartosz Golaszewski 	mutex_lock(&nvmem_cell_mutex);
490b985f4cbSBartosz Golaszewski 	list_for_each_entry(table, &nvmem_cell_tables, node) {
491b985f4cbSBartosz Golaszewski 		if (strcmp(nvmem_dev_name(nvmem), table->nvmem_name) == 0) {
492b985f4cbSBartosz Golaszewski 			for (i = 0; i < table->ncells; i++) {
493b985f4cbSBartosz Golaszewski 				info = &table->cells[i];
494b985f4cbSBartosz Golaszewski 
495b985f4cbSBartosz Golaszewski 				cell = kzalloc(sizeof(*cell), GFP_KERNEL);
496b985f4cbSBartosz Golaszewski 				if (!cell) {
497b985f4cbSBartosz Golaszewski 					rval = -ENOMEM;
498b985f4cbSBartosz Golaszewski 					goto out;
499b985f4cbSBartosz Golaszewski 				}
500b985f4cbSBartosz Golaszewski 
501b985f4cbSBartosz Golaszewski 				rval = nvmem_cell_info_to_nvmem_cell(nvmem,
502b985f4cbSBartosz Golaszewski 								     info,
503b985f4cbSBartosz Golaszewski 								     cell);
504b985f4cbSBartosz Golaszewski 				if (rval) {
505b985f4cbSBartosz Golaszewski 					kfree(cell);
506b985f4cbSBartosz Golaszewski 					goto out;
507b985f4cbSBartosz Golaszewski 				}
508b985f4cbSBartosz Golaszewski 
509b985f4cbSBartosz Golaszewski 				nvmem_cell_add(cell);
510b985f4cbSBartosz Golaszewski 			}
511b985f4cbSBartosz Golaszewski 		}
512b985f4cbSBartosz Golaszewski 	}
513b985f4cbSBartosz Golaszewski 
514b985f4cbSBartosz Golaszewski out:
515b985f4cbSBartosz Golaszewski 	mutex_unlock(&nvmem_cell_mutex);
516b985f4cbSBartosz Golaszewski 	return rval;
517b985f4cbSBartosz Golaszewski }
518b985f4cbSBartosz Golaszewski 
519e888d445SBartosz Golaszewski static struct nvmem_cell *
520506157beSBartosz Golaszewski nvmem_find_cell_by_name(struct nvmem_device *nvmem, const char *cell_id)
521506157beSBartosz Golaszewski {
5221c832674SAlban Bedel 	struct nvmem_cell *iter, *cell = NULL;
523506157beSBartosz Golaszewski 
524506157beSBartosz Golaszewski 	mutex_lock(&nvmem_mutex);
5251c832674SAlban Bedel 	list_for_each_entry(iter, &nvmem->cells, node) {
5261c832674SAlban Bedel 		if (strcmp(cell_id, iter->name) == 0) {
5271c832674SAlban Bedel 			cell = iter;
528506157beSBartosz Golaszewski 			break;
529506157beSBartosz Golaszewski 		}
5301c832674SAlban Bedel 	}
531506157beSBartosz Golaszewski 	mutex_unlock(&nvmem_mutex);
532506157beSBartosz Golaszewski 
533506157beSBartosz Golaszewski 	return cell;
534506157beSBartosz Golaszewski }
535506157beSBartosz Golaszewski 
536e888d445SBartosz Golaszewski static int nvmem_add_cells_from_of(struct nvmem_device *nvmem)
537e888d445SBartosz Golaszewski {
538e888d445SBartosz Golaszewski 	struct device_node *parent, *child;
539e888d445SBartosz Golaszewski 	struct device *dev = &nvmem->dev;
540e888d445SBartosz Golaszewski 	struct nvmem_cell *cell;
541e888d445SBartosz Golaszewski 	const __be32 *addr;
542e888d445SBartosz Golaszewski 	int len;
543e888d445SBartosz Golaszewski 
544e888d445SBartosz Golaszewski 	parent = dev->of_node;
545e888d445SBartosz Golaszewski 
546e888d445SBartosz Golaszewski 	for_each_child_of_node(parent, child) {
547e888d445SBartosz Golaszewski 		addr = of_get_property(child, "reg", &len);
548e888d445SBartosz Golaszewski 		if (!addr || (len < 2 * sizeof(u32))) {
549e888d445SBartosz Golaszewski 			dev_err(dev, "nvmem: invalid reg on %pOF\n", child);
550e888d445SBartosz Golaszewski 			return -EINVAL;
551e888d445SBartosz Golaszewski 		}
552e888d445SBartosz Golaszewski 
553e888d445SBartosz Golaszewski 		cell = kzalloc(sizeof(*cell), GFP_KERNEL);
554e888d445SBartosz Golaszewski 		if (!cell)
555e888d445SBartosz Golaszewski 			return -ENOMEM;
556e888d445SBartosz Golaszewski 
557e888d445SBartosz Golaszewski 		cell->nvmem = nvmem;
5580749aa25SSrinivas Kandagatla 		cell->np = of_node_get(child);
559e888d445SBartosz Golaszewski 		cell->offset = be32_to_cpup(addr++);
560e888d445SBartosz Golaszewski 		cell->bytes = be32_to_cpup(addr);
561badcdff1SRob Herring 		cell->name = kasprintf(GFP_KERNEL, "%pOFn", child);
562e888d445SBartosz Golaszewski 
563e888d445SBartosz Golaszewski 		addr = of_get_property(child, "bits", &len);
564e888d445SBartosz Golaszewski 		if (addr && len == (2 * sizeof(u32))) {
565e888d445SBartosz Golaszewski 			cell->bit_offset = be32_to_cpup(addr++);
566e888d445SBartosz Golaszewski 			cell->nbits = be32_to_cpup(addr);
567e888d445SBartosz Golaszewski 		}
568e888d445SBartosz Golaszewski 
569e888d445SBartosz Golaszewski 		if (cell->nbits)
570e888d445SBartosz Golaszewski 			cell->bytes = DIV_ROUND_UP(
571e888d445SBartosz Golaszewski 					cell->nbits + cell->bit_offset,
572e888d445SBartosz Golaszewski 					BITS_PER_BYTE);
573e888d445SBartosz Golaszewski 
574e888d445SBartosz Golaszewski 		if (!IS_ALIGNED(cell->offset, nvmem->stride)) {
575e888d445SBartosz Golaszewski 			dev_err(dev, "cell %s unaligned to nvmem stride %d\n",
576e888d445SBartosz Golaszewski 				cell->name, nvmem->stride);
577e888d445SBartosz Golaszewski 			/* Cells already added will be freed later. */
57816bb7abcSBitan Biswas 			kfree_const(cell->name);
579e888d445SBartosz Golaszewski 			kfree(cell);
580e888d445SBartosz Golaszewski 			return -EINVAL;
581e888d445SBartosz Golaszewski 		}
582e888d445SBartosz Golaszewski 
583e888d445SBartosz Golaszewski 		nvmem_cell_add(cell);
584e888d445SBartosz Golaszewski 	}
585e888d445SBartosz Golaszewski 
586e888d445SBartosz Golaszewski 	return 0;
587e888d445SBartosz Golaszewski }
588e888d445SBartosz Golaszewski 
589eace75cfSSrinivas Kandagatla /**
590eace75cfSSrinivas Kandagatla  * nvmem_register() - Register a nvmem device for given nvmem_config.
5913a758071SAndreas Färber  * Also creates a binary entry in /sys/bus/nvmem/devices/dev-name/nvmem
592eace75cfSSrinivas Kandagatla  *
593eace75cfSSrinivas Kandagatla  * @config: nvmem device configuration with which nvmem device is created.
594eace75cfSSrinivas Kandagatla  *
595eace75cfSSrinivas Kandagatla  * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device
596eace75cfSSrinivas Kandagatla  * on success.
597eace75cfSSrinivas Kandagatla  */
598eace75cfSSrinivas Kandagatla 
599eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem_register(const struct nvmem_config *config)
600eace75cfSSrinivas Kandagatla {
601eace75cfSSrinivas Kandagatla 	struct nvmem_device *nvmem;
602eace75cfSSrinivas Kandagatla 	int rval;
603eace75cfSSrinivas Kandagatla 
604eace75cfSSrinivas Kandagatla 	if (!config->dev)
605eace75cfSSrinivas Kandagatla 		return ERR_PTR(-EINVAL);
606eace75cfSSrinivas Kandagatla 
607061a320bSSrinivas Kandagatla 	if (!config->reg_read && !config->reg_write)
608061a320bSSrinivas Kandagatla 		return ERR_PTR(-EINVAL);
609061a320bSSrinivas Kandagatla 
610eace75cfSSrinivas Kandagatla 	nvmem = kzalloc(sizeof(*nvmem), GFP_KERNEL);
611eace75cfSSrinivas Kandagatla 	if (!nvmem)
612eace75cfSSrinivas Kandagatla 		return ERR_PTR(-ENOMEM);
613eace75cfSSrinivas Kandagatla 
6141eb51d6aSBartosz Golaszewski 	rval  = ida_alloc(&nvmem_ida, GFP_KERNEL);
615eace75cfSSrinivas Kandagatla 	if (rval < 0) {
616eace75cfSSrinivas Kandagatla 		kfree(nvmem);
617eace75cfSSrinivas Kandagatla 		return ERR_PTR(rval);
618eace75cfSSrinivas Kandagatla 	}
61931c6ff51SBartosz Golaszewski 
6202a127da4SKhouloud Touil 	if (config->wp_gpio)
6212a127da4SKhouloud Touil 		nvmem->wp_gpio = config->wp_gpio;
6222a127da4SKhouloud Touil 	else
6232a127da4SKhouloud Touil 		nvmem->wp_gpio = gpiod_get_optional(config->dev, "wp",
6242a127da4SKhouloud Touil 						    GPIOD_OUT_HIGH);
625f7d8d7dcSBartosz Golaszewski 	if (IS_ERR(nvmem->wp_gpio)) {
6261eb51d6aSBartosz Golaszewski 		ida_free(&nvmem_ida, nvmem->id);
627f7d8d7dcSBartosz Golaszewski 		rval = PTR_ERR(nvmem->wp_gpio);
628f7d8d7dcSBartosz Golaszewski 		kfree(nvmem);
629f7d8d7dcSBartosz Golaszewski 		return ERR_PTR(rval);
630f7d8d7dcSBartosz Golaszewski 	}
6312a127da4SKhouloud Touil 
632c1de7f43SBartosz Golaszewski 	kref_init(&nvmem->refcnt);
633c7235ee3SBartosz Golaszewski 	INIT_LIST_HEAD(&nvmem->cells);
634c1de7f43SBartosz Golaszewski 
635eace75cfSSrinivas Kandagatla 	nvmem->id = rval;
636eace75cfSSrinivas Kandagatla 	nvmem->owner = config->owner;
63717eb18d6SMasahiro Yamada 	if (!nvmem->owner && config->dev->driver)
63817eb18d6SMasahiro Yamada 		nvmem->owner = config->dev->driver->owner;
63999897efdSHeiner Kallweit 	nvmem->stride = config->stride ?: 1;
64099897efdSHeiner Kallweit 	nvmem->word_size = config->word_size ?: 1;
641795ddd18SSrinivas Kandagatla 	nvmem->size = config->size;
642eace75cfSSrinivas Kandagatla 	nvmem->dev.type = &nvmem_provider_type;
643eace75cfSSrinivas Kandagatla 	nvmem->dev.bus = &nvmem_bus_type;
644eace75cfSSrinivas Kandagatla 	nvmem->dev.parent = config->dev;
645e6de179dSSrinivas Kandagatla 	nvmem->root_only = config->root_only;
646795ddd18SSrinivas Kandagatla 	nvmem->priv = config->priv;
64716688453SAlexandre Belloni 	nvmem->type = config->type;
648795ddd18SSrinivas Kandagatla 	nvmem->reg_read = config->reg_read;
649795ddd18SSrinivas Kandagatla 	nvmem->reg_write = config->reg_write;
650517f14d9SBartosz Golaszewski 	if (!config->no_of_node)
651fc2f9970SHeiner Kallweit 		nvmem->dev.of_node = config->dev->of_node;
652fd0f4906SAndrey Smirnov 
653731aa3faSSrinivas Kandagatla 	switch (config->id) {
654731aa3faSSrinivas Kandagatla 	case NVMEM_DEVID_NONE:
655fd0f4906SAndrey Smirnov 		dev_set_name(&nvmem->dev, "%s", config->name);
656731aa3faSSrinivas Kandagatla 		break;
657731aa3faSSrinivas Kandagatla 	case NVMEM_DEVID_AUTO:
658731aa3faSSrinivas Kandagatla 		dev_set_name(&nvmem->dev, "%s%d", config->name, nvmem->id);
659731aa3faSSrinivas Kandagatla 		break;
660731aa3faSSrinivas Kandagatla 	default:
661eace75cfSSrinivas Kandagatla 		dev_set_name(&nvmem->dev, "%s%d",
6625253193dSAban Bedel 			     config->name ? : "nvmem",
6635253193dSAban Bedel 			     config->name ? config->id : nvmem->id);
664731aa3faSSrinivas Kandagatla 		break;
665fd0f4906SAndrey Smirnov 	}
666eace75cfSSrinivas Kandagatla 
6671716cfe8SAlban Bedel 	nvmem->read_only = device_property_present(config->dev, "read-only") ||
6681716cfe8SAlban Bedel 			   config->read_only || !nvmem->reg_write;
669eace75cfSSrinivas Kandagatla 
67084400305SSrinivas Kandagatla #ifdef CONFIG_NVMEM_SYSFS
67184400305SSrinivas Kandagatla 	nvmem->dev.groups = nvmem_dev_groups;
67284400305SSrinivas Kandagatla #endif
673eace75cfSSrinivas Kandagatla 
674eace75cfSSrinivas Kandagatla 	dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name);
675eace75cfSSrinivas Kandagatla 
676f60442ddSSrinivas Kandagatla 	rval = device_register(&nvmem->dev);
677b6c217abSAndrew Lunn 	if (rval)
6783360acdfSJohan Hovold 		goto err_put_device;
679b6c217abSAndrew Lunn 
680b6c217abSAndrew Lunn 	if (config->compat) {
681ae0c2d72SSrinivas Kandagatla 		rval = nvmem_sysfs_setup_compat(nvmem, config);
682b6c217abSAndrew Lunn 		if (rval)
6833360acdfSJohan Hovold 			goto err_device_del;
684eace75cfSSrinivas Kandagatla 	}
685eace75cfSSrinivas Kandagatla 
686fa72d847SBartosz Golaszewski 	if (config->cells) {
687fa72d847SBartosz Golaszewski 		rval = nvmem_add_cells(nvmem, config->cells, config->ncells);
688fa72d847SBartosz Golaszewski 		if (rval)
689fa72d847SBartosz Golaszewski 			goto err_teardown_compat;
690fa72d847SBartosz Golaszewski 	}
691eace75cfSSrinivas Kandagatla 
692b985f4cbSBartosz Golaszewski 	rval = nvmem_add_cells_from_table(nvmem);
693b985f4cbSBartosz Golaszewski 	if (rval)
694b985f4cbSBartosz Golaszewski 		goto err_remove_cells;
695b985f4cbSBartosz Golaszewski 
696e888d445SBartosz Golaszewski 	rval = nvmem_add_cells_from_of(nvmem);
697e888d445SBartosz Golaszewski 	if (rval)
698e888d445SBartosz Golaszewski 		goto err_remove_cells;
699e888d445SBartosz Golaszewski 
700f4853e1cSBartosz Golaszewski 	blocking_notifier_call_chain(&nvmem_notifier, NVMEM_ADD, nvmem);
701bee1138bSBartosz Golaszewski 
702eace75cfSSrinivas Kandagatla 	return nvmem;
7033360acdfSJohan Hovold 
704b985f4cbSBartosz Golaszewski err_remove_cells:
705b985f4cbSBartosz Golaszewski 	nvmem_device_remove_all_cells(nvmem);
706fa72d847SBartosz Golaszewski err_teardown_compat:
707fa72d847SBartosz Golaszewski 	if (config->compat)
708ae0c2d72SSrinivas Kandagatla 		nvmem_sysfs_remove_compat(nvmem, config);
7093360acdfSJohan Hovold err_device_del:
7103360acdfSJohan Hovold 	device_del(&nvmem->dev);
7113360acdfSJohan Hovold err_put_device:
7123360acdfSJohan Hovold 	put_device(&nvmem->dev);
7133360acdfSJohan Hovold 
714b6c217abSAndrew Lunn 	return ERR_PTR(rval);
715eace75cfSSrinivas Kandagatla }
716eace75cfSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_register);
717eace75cfSSrinivas Kandagatla 
718c1de7f43SBartosz Golaszewski static void nvmem_device_release(struct kref *kref)
719c1de7f43SBartosz Golaszewski {
720c1de7f43SBartosz Golaszewski 	struct nvmem_device *nvmem;
721c1de7f43SBartosz Golaszewski 
722c1de7f43SBartosz Golaszewski 	nvmem = container_of(kref, struct nvmem_device, refcnt);
723c1de7f43SBartosz Golaszewski 
724bee1138bSBartosz Golaszewski 	blocking_notifier_call_chain(&nvmem_notifier, NVMEM_REMOVE, nvmem);
725bee1138bSBartosz Golaszewski 
726c1de7f43SBartosz Golaszewski 	if (nvmem->flags & FLAG_COMPAT)
727c1de7f43SBartosz Golaszewski 		device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom);
728c1de7f43SBartosz Golaszewski 
729c1de7f43SBartosz Golaszewski 	nvmem_device_remove_all_cells(nvmem);
730f60442ddSSrinivas Kandagatla 	device_unregister(&nvmem->dev);
731c1de7f43SBartosz Golaszewski }
732c1de7f43SBartosz Golaszewski 
733eace75cfSSrinivas Kandagatla /**
734eace75cfSSrinivas Kandagatla  * nvmem_unregister() - Unregister previously registered nvmem device
735eace75cfSSrinivas Kandagatla  *
736eace75cfSSrinivas Kandagatla  * @nvmem: Pointer to previously registered nvmem device.
737eace75cfSSrinivas Kandagatla  */
738bf58e882SBartosz Golaszewski void nvmem_unregister(struct nvmem_device *nvmem)
739eace75cfSSrinivas Kandagatla {
740c1de7f43SBartosz Golaszewski 	kref_put(&nvmem->refcnt, nvmem_device_release);
741eace75cfSSrinivas Kandagatla }
742eace75cfSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_unregister);
743eace75cfSSrinivas Kandagatla 
744f1f50ecaSAndrey Smirnov static void devm_nvmem_release(struct device *dev, void *res)
745f1f50ecaSAndrey Smirnov {
746bf58e882SBartosz Golaszewski 	nvmem_unregister(*(struct nvmem_device **)res);
747f1f50ecaSAndrey Smirnov }
748f1f50ecaSAndrey Smirnov 
749f1f50ecaSAndrey Smirnov /**
750f1f50ecaSAndrey Smirnov  * devm_nvmem_register() - Register a managed nvmem device for given
751f1f50ecaSAndrey Smirnov  * nvmem_config.
7523a758071SAndreas Färber  * Also creates a binary entry in /sys/bus/nvmem/devices/dev-name/nvmem
753f1f50ecaSAndrey Smirnov  *
754b378c779SSrinivas Kandagatla  * @dev: Device that uses the nvmem device.
755f1f50ecaSAndrey Smirnov  * @config: nvmem device configuration with which nvmem device is created.
756f1f50ecaSAndrey Smirnov  *
757f1f50ecaSAndrey Smirnov  * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device
758f1f50ecaSAndrey Smirnov  * on success.
759f1f50ecaSAndrey Smirnov  */
760f1f50ecaSAndrey Smirnov struct nvmem_device *devm_nvmem_register(struct device *dev,
761f1f50ecaSAndrey Smirnov 					 const struct nvmem_config *config)
762f1f50ecaSAndrey Smirnov {
763f1f50ecaSAndrey Smirnov 	struct nvmem_device **ptr, *nvmem;
764f1f50ecaSAndrey Smirnov 
765f1f50ecaSAndrey Smirnov 	ptr = devres_alloc(devm_nvmem_release, sizeof(*ptr), GFP_KERNEL);
766f1f50ecaSAndrey Smirnov 	if (!ptr)
767f1f50ecaSAndrey Smirnov 		return ERR_PTR(-ENOMEM);
768f1f50ecaSAndrey Smirnov 
769f1f50ecaSAndrey Smirnov 	nvmem = nvmem_register(config);
770f1f50ecaSAndrey Smirnov 
771f1f50ecaSAndrey Smirnov 	if (!IS_ERR(nvmem)) {
772f1f50ecaSAndrey Smirnov 		*ptr = nvmem;
773f1f50ecaSAndrey Smirnov 		devres_add(dev, ptr);
774f1f50ecaSAndrey Smirnov 	} else {
775f1f50ecaSAndrey Smirnov 		devres_free(ptr);
776f1f50ecaSAndrey Smirnov 	}
777f1f50ecaSAndrey Smirnov 
778f1f50ecaSAndrey Smirnov 	return nvmem;
779f1f50ecaSAndrey Smirnov }
780f1f50ecaSAndrey Smirnov EXPORT_SYMBOL_GPL(devm_nvmem_register);
781f1f50ecaSAndrey Smirnov 
782f1f50ecaSAndrey Smirnov static int devm_nvmem_match(struct device *dev, void *res, void *data)
783f1f50ecaSAndrey Smirnov {
784f1f50ecaSAndrey Smirnov 	struct nvmem_device **r = res;
785f1f50ecaSAndrey Smirnov 
786f1f50ecaSAndrey Smirnov 	return *r == data;
787f1f50ecaSAndrey Smirnov }
788f1f50ecaSAndrey Smirnov 
789f1f50ecaSAndrey Smirnov /**
790f1f50ecaSAndrey Smirnov  * devm_nvmem_unregister() - Unregister previously registered managed nvmem
791f1f50ecaSAndrey Smirnov  * device.
792f1f50ecaSAndrey Smirnov  *
793b378c779SSrinivas Kandagatla  * @dev: Device that uses the nvmem device.
794f1f50ecaSAndrey Smirnov  * @nvmem: Pointer to previously registered nvmem device.
795f1f50ecaSAndrey Smirnov  *
7963a758071SAndreas Färber  * Return: Will be negative on error or zero on success.
797f1f50ecaSAndrey Smirnov  */
798f1f50ecaSAndrey Smirnov int devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem)
799f1f50ecaSAndrey Smirnov {
800f1f50ecaSAndrey Smirnov 	return devres_release(dev, devm_nvmem_release, devm_nvmem_match, nvmem);
801f1f50ecaSAndrey Smirnov }
802f1f50ecaSAndrey Smirnov EXPORT_SYMBOL(devm_nvmem_unregister);
803f1f50ecaSAndrey Smirnov 
8048c2a2b8cSThomas Bogendoerfer static struct nvmem_device *__nvmem_device_get(void *data,
8058c2a2b8cSThomas Bogendoerfer 			int (*match)(struct device *dev, const void *data))
80669aba794SSrinivas Kandagatla {
80769aba794SSrinivas Kandagatla 	struct nvmem_device *nvmem = NULL;
8088c2a2b8cSThomas Bogendoerfer 	struct device *dev;
80969aba794SSrinivas Kandagatla 
810c7235ee3SBartosz Golaszewski 	mutex_lock(&nvmem_mutex);
8118c2a2b8cSThomas Bogendoerfer 	dev = bus_find_device(&nvmem_bus_type, NULL, data, match);
8128c2a2b8cSThomas Bogendoerfer 	if (dev)
8138c2a2b8cSThomas Bogendoerfer 		nvmem = to_nvmem_device(dev);
81469aba794SSrinivas Kandagatla 	mutex_unlock(&nvmem_mutex);
815c7235ee3SBartosz Golaszewski 	if (!nvmem)
816c7235ee3SBartosz Golaszewski 		return ERR_PTR(-EPROBE_DEFER);
81769aba794SSrinivas Kandagatla 
81869aba794SSrinivas Kandagatla 	if (!try_module_get(nvmem->owner)) {
81969aba794SSrinivas Kandagatla 		dev_err(&nvmem->dev,
82069aba794SSrinivas Kandagatla 			"could not increase module refcount for cell %s\n",
8215db652c9SBartosz Golaszewski 			nvmem_dev_name(nvmem));
82269aba794SSrinivas Kandagatla 
82373e9dc4dSAlban Bedel 		put_device(&nvmem->dev);
82469aba794SSrinivas Kandagatla 		return ERR_PTR(-EINVAL);
82569aba794SSrinivas Kandagatla 	}
82669aba794SSrinivas Kandagatla 
827c1de7f43SBartosz Golaszewski 	kref_get(&nvmem->refcnt);
828c1de7f43SBartosz Golaszewski 
82969aba794SSrinivas Kandagatla 	return nvmem;
83069aba794SSrinivas Kandagatla }
83169aba794SSrinivas Kandagatla 
83269aba794SSrinivas Kandagatla static void __nvmem_device_put(struct nvmem_device *nvmem)
83369aba794SSrinivas Kandagatla {
83473e9dc4dSAlban Bedel 	put_device(&nvmem->dev);
83569aba794SSrinivas Kandagatla 	module_put(nvmem->owner);
836c1de7f43SBartosz Golaszewski 	kref_put(&nvmem->refcnt, nvmem_device_release);
83769aba794SSrinivas Kandagatla }
83869aba794SSrinivas Kandagatla 
839e701c67cSMasahiro Yamada #if IS_ENABLED(CONFIG_OF)
840e2a5402eSSrinivas Kandagatla /**
841e2a5402eSSrinivas Kandagatla  * of_nvmem_device_get() - Get nvmem device from a given id
842e2a5402eSSrinivas Kandagatla  *
84329143268SVivek Gautam  * @np: Device tree node that uses the nvmem device.
844e2a5402eSSrinivas Kandagatla  * @id: nvmem name from nvmem-names property.
845e2a5402eSSrinivas Kandagatla  *
846e2a5402eSSrinivas Kandagatla  * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device
847e2a5402eSSrinivas Kandagatla  * on success.
848e2a5402eSSrinivas Kandagatla  */
849e2a5402eSSrinivas Kandagatla struct nvmem_device *of_nvmem_device_get(struct device_node *np, const char *id)
850e2a5402eSSrinivas Kandagatla {
851e2a5402eSSrinivas Kandagatla 
852e2a5402eSSrinivas Kandagatla 	struct device_node *nvmem_np;
853b1c194dcSVadym Kochan 	struct nvmem_device *nvmem;
854d4e7fef1SAlban Bedel 	int index = 0;
855e2a5402eSSrinivas Kandagatla 
856d4e7fef1SAlban Bedel 	if (id)
857e2a5402eSSrinivas Kandagatla 		index = of_property_match_string(np, "nvmem-names", id);
858e2a5402eSSrinivas Kandagatla 
859e2a5402eSSrinivas Kandagatla 	nvmem_np = of_parse_phandle(np, "nvmem", index);
860e2a5402eSSrinivas Kandagatla 	if (!nvmem_np)
861d4e7fef1SAlban Bedel 		return ERR_PTR(-ENOENT);
862e2a5402eSSrinivas Kandagatla 
863b1c194dcSVadym Kochan 	nvmem = __nvmem_device_get(nvmem_np, device_match_of_node);
864b1c194dcSVadym Kochan 	of_node_put(nvmem_np);
865b1c194dcSVadym Kochan 	return nvmem;
866e2a5402eSSrinivas Kandagatla }
867e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_nvmem_device_get);
868e2a5402eSSrinivas Kandagatla #endif
869e2a5402eSSrinivas Kandagatla 
870e2a5402eSSrinivas Kandagatla /**
871e2a5402eSSrinivas Kandagatla  * nvmem_device_get() - Get nvmem device from a given id
872e2a5402eSSrinivas Kandagatla  *
87329143268SVivek Gautam  * @dev: Device that uses the nvmem device.
87429143268SVivek Gautam  * @dev_name: name of the requested nvmem device.
875e2a5402eSSrinivas Kandagatla  *
876e2a5402eSSrinivas Kandagatla  * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device
877e2a5402eSSrinivas Kandagatla  * on success.
878e2a5402eSSrinivas Kandagatla  */
879e2a5402eSSrinivas Kandagatla struct nvmem_device *nvmem_device_get(struct device *dev, const char *dev_name)
880e2a5402eSSrinivas Kandagatla {
881e2a5402eSSrinivas Kandagatla 	if (dev->of_node) { /* try dt first */
882e2a5402eSSrinivas Kandagatla 		struct nvmem_device *nvmem;
883e2a5402eSSrinivas Kandagatla 
884e2a5402eSSrinivas Kandagatla 		nvmem = of_nvmem_device_get(dev->of_node, dev_name);
885e2a5402eSSrinivas Kandagatla 
886e2a5402eSSrinivas Kandagatla 		if (!IS_ERR(nvmem) || PTR_ERR(nvmem) == -EPROBE_DEFER)
887e2a5402eSSrinivas Kandagatla 			return nvmem;
888e2a5402eSSrinivas Kandagatla 
889e2a5402eSSrinivas Kandagatla 	}
890e2a5402eSSrinivas Kandagatla 
8918c2a2b8cSThomas Bogendoerfer 	return __nvmem_device_get((void *)dev_name, device_match_name);
892e2a5402eSSrinivas Kandagatla }
893e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_get);
894e2a5402eSSrinivas Kandagatla 
8958c2a2b8cSThomas Bogendoerfer /**
8968c2a2b8cSThomas Bogendoerfer  * nvmem_device_find() - Find nvmem device with matching function
8978c2a2b8cSThomas Bogendoerfer  *
8988c2a2b8cSThomas Bogendoerfer  * @data: Data to pass to match function
8998c2a2b8cSThomas Bogendoerfer  * @match: Callback function to check device
9008c2a2b8cSThomas Bogendoerfer  *
9018c2a2b8cSThomas Bogendoerfer  * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device
9028c2a2b8cSThomas Bogendoerfer  * on success.
9038c2a2b8cSThomas Bogendoerfer  */
9048c2a2b8cSThomas Bogendoerfer struct nvmem_device *nvmem_device_find(void *data,
9058c2a2b8cSThomas Bogendoerfer 			int (*match)(struct device *dev, const void *data))
9068c2a2b8cSThomas Bogendoerfer {
9078c2a2b8cSThomas Bogendoerfer 	return __nvmem_device_get(data, match);
9088c2a2b8cSThomas Bogendoerfer }
9098c2a2b8cSThomas Bogendoerfer EXPORT_SYMBOL_GPL(nvmem_device_find);
9108c2a2b8cSThomas Bogendoerfer 
911e2a5402eSSrinivas Kandagatla static int devm_nvmem_device_match(struct device *dev, void *res, void *data)
912e2a5402eSSrinivas Kandagatla {
913e2a5402eSSrinivas Kandagatla 	struct nvmem_device **nvmem = res;
914e2a5402eSSrinivas Kandagatla 
915e2a5402eSSrinivas Kandagatla 	if (WARN_ON(!nvmem || !*nvmem))
916e2a5402eSSrinivas Kandagatla 		return 0;
917e2a5402eSSrinivas Kandagatla 
918e2a5402eSSrinivas Kandagatla 	return *nvmem == data;
919e2a5402eSSrinivas Kandagatla }
920e2a5402eSSrinivas Kandagatla 
921e2a5402eSSrinivas Kandagatla static void devm_nvmem_device_release(struct device *dev, void *res)
922e2a5402eSSrinivas Kandagatla {
923e2a5402eSSrinivas Kandagatla 	nvmem_device_put(*(struct nvmem_device **)res);
924e2a5402eSSrinivas Kandagatla }
925e2a5402eSSrinivas Kandagatla 
926e2a5402eSSrinivas Kandagatla /**
927e2a5402eSSrinivas Kandagatla  * devm_nvmem_device_put() - put alredy got nvmem device
928e2a5402eSSrinivas Kandagatla  *
92929143268SVivek Gautam  * @dev: Device that uses the nvmem device.
930e2a5402eSSrinivas Kandagatla  * @nvmem: pointer to nvmem device allocated by devm_nvmem_cell_get(),
931e2a5402eSSrinivas Kandagatla  * that needs to be released.
932e2a5402eSSrinivas Kandagatla  */
933e2a5402eSSrinivas Kandagatla void devm_nvmem_device_put(struct device *dev, struct nvmem_device *nvmem)
934e2a5402eSSrinivas Kandagatla {
935e2a5402eSSrinivas Kandagatla 	int ret;
936e2a5402eSSrinivas Kandagatla 
937e2a5402eSSrinivas Kandagatla 	ret = devres_release(dev, devm_nvmem_device_release,
938e2a5402eSSrinivas Kandagatla 			     devm_nvmem_device_match, nvmem);
939e2a5402eSSrinivas Kandagatla 
940e2a5402eSSrinivas Kandagatla 	WARN_ON(ret);
941e2a5402eSSrinivas Kandagatla }
942e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_device_put);
943e2a5402eSSrinivas Kandagatla 
944e2a5402eSSrinivas Kandagatla /**
945e2a5402eSSrinivas Kandagatla  * nvmem_device_put() - put alredy got nvmem device
946e2a5402eSSrinivas Kandagatla  *
947e2a5402eSSrinivas Kandagatla  * @nvmem: pointer to nvmem device that needs to be released.
948e2a5402eSSrinivas Kandagatla  */
949e2a5402eSSrinivas Kandagatla void nvmem_device_put(struct nvmem_device *nvmem)
950e2a5402eSSrinivas Kandagatla {
951e2a5402eSSrinivas Kandagatla 	__nvmem_device_put(nvmem);
952e2a5402eSSrinivas Kandagatla }
953e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_put);
954e2a5402eSSrinivas Kandagatla 
955e2a5402eSSrinivas Kandagatla /**
956e2a5402eSSrinivas Kandagatla  * devm_nvmem_device_get() - Get nvmem cell of device form a given id
957e2a5402eSSrinivas Kandagatla  *
95829143268SVivek Gautam  * @dev: Device that requests the nvmem device.
95929143268SVivek Gautam  * @id: name id for the requested nvmem device.
960e2a5402eSSrinivas Kandagatla  *
961e2a5402eSSrinivas Kandagatla  * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_cell
962e2a5402eSSrinivas Kandagatla  * on success.  The nvmem_cell will be freed by the automatically once the
963e2a5402eSSrinivas Kandagatla  * device is freed.
964e2a5402eSSrinivas Kandagatla  */
965e2a5402eSSrinivas Kandagatla struct nvmem_device *devm_nvmem_device_get(struct device *dev, const char *id)
966e2a5402eSSrinivas Kandagatla {
967e2a5402eSSrinivas Kandagatla 	struct nvmem_device **ptr, *nvmem;
968e2a5402eSSrinivas Kandagatla 
969e2a5402eSSrinivas Kandagatla 	ptr = devres_alloc(devm_nvmem_device_release, sizeof(*ptr), GFP_KERNEL);
970e2a5402eSSrinivas Kandagatla 	if (!ptr)
971e2a5402eSSrinivas Kandagatla 		return ERR_PTR(-ENOMEM);
972e2a5402eSSrinivas Kandagatla 
973e2a5402eSSrinivas Kandagatla 	nvmem = nvmem_device_get(dev, id);
974e2a5402eSSrinivas Kandagatla 	if (!IS_ERR(nvmem)) {
975e2a5402eSSrinivas Kandagatla 		*ptr = nvmem;
976e2a5402eSSrinivas Kandagatla 		devres_add(dev, ptr);
977e2a5402eSSrinivas Kandagatla 	} else {
978e2a5402eSSrinivas Kandagatla 		devres_free(ptr);
979e2a5402eSSrinivas Kandagatla 	}
980e2a5402eSSrinivas Kandagatla 
981e2a5402eSSrinivas Kandagatla 	return nvmem;
982e2a5402eSSrinivas Kandagatla }
983e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_device_get);
984e2a5402eSSrinivas Kandagatla 
985506157beSBartosz Golaszewski static struct nvmem_cell *
986506157beSBartosz Golaszewski nvmem_cell_get_from_lookup(struct device *dev, const char *con_id)
98769aba794SSrinivas Kandagatla {
988506157beSBartosz Golaszewski 	struct nvmem_cell *cell = ERR_PTR(-ENOENT);
989506157beSBartosz Golaszewski 	struct nvmem_cell_lookup *lookup;
99069aba794SSrinivas Kandagatla 	struct nvmem_device *nvmem;
991506157beSBartosz Golaszewski 	const char *dev_id;
99269aba794SSrinivas Kandagatla 
993506157beSBartosz Golaszewski 	if (!dev)
994506157beSBartosz Golaszewski 		return ERR_PTR(-EINVAL);
99569aba794SSrinivas Kandagatla 
996506157beSBartosz Golaszewski 	dev_id = dev_name(dev);
997506157beSBartosz Golaszewski 
998506157beSBartosz Golaszewski 	mutex_lock(&nvmem_lookup_mutex);
999506157beSBartosz Golaszewski 
1000506157beSBartosz Golaszewski 	list_for_each_entry(lookup, &nvmem_lookup_list, node) {
1001506157beSBartosz Golaszewski 		if ((strcmp(lookup->dev_id, dev_id) == 0) &&
1002506157beSBartosz Golaszewski 		    (strcmp(lookup->con_id, con_id) == 0)) {
1003506157beSBartosz Golaszewski 			/* This is the right entry. */
10048c2a2b8cSThomas Bogendoerfer 			nvmem = __nvmem_device_get((void *)lookup->nvmem_name,
10058c2a2b8cSThomas Bogendoerfer 						   device_match_name);
1006cccb3b19SBartosz Golaszewski 			if (IS_ERR(nvmem)) {
1007506157beSBartosz Golaszewski 				/* Provider may not be registered yet. */
1008cccb3b19SBartosz Golaszewski 				cell = ERR_CAST(nvmem);
10099bfd8198SAlban Bedel 				break;
1010506157beSBartosz Golaszewski 			}
1011506157beSBartosz Golaszewski 
1012506157beSBartosz Golaszewski 			cell = nvmem_find_cell_by_name(nvmem,
1013506157beSBartosz Golaszewski 						       lookup->cell_name);
1014506157beSBartosz Golaszewski 			if (!cell) {
1015506157beSBartosz Golaszewski 				__nvmem_device_put(nvmem);
1016cccb3b19SBartosz Golaszewski 				cell = ERR_PTR(-ENOENT);
1017506157beSBartosz Golaszewski 			}
10189bfd8198SAlban Bedel 			break;
1019506157beSBartosz Golaszewski 		}
1020506157beSBartosz Golaszewski 	}
1021506157beSBartosz Golaszewski 
1022506157beSBartosz Golaszewski 	mutex_unlock(&nvmem_lookup_mutex);
102369aba794SSrinivas Kandagatla 	return cell;
102469aba794SSrinivas Kandagatla }
102569aba794SSrinivas Kandagatla 
1026e701c67cSMasahiro Yamada #if IS_ENABLED(CONFIG_OF)
10273c53e235SArnd Bergmann static struct nvmem_cell *
10280749aa25SSrinivas Kandagatla nvmem_find_cell_by_node(struct nvmem_device *nvmem, struct device_node *np)
10293c53e235SArnd Bergmann {
10301c832674SAlban Bedel 	struct nvmem_cell *iter, *cell = NULL;
10313c53e235SArnd Bergmann 
10323c53e235SArnd Bergmann 	mutex_lock(&nvmem_mutex);
10331c832674SAlban Bedel 	list_for_each_entry(iter, &nvmem->cells, node) {
10341c832674SAlban Bedel 		if (np == iter->np) {
10351c832674SAlban Bedel 			cell = iter;
10363c53e235SArnd Bergmann 			break;
10373c53e235SArnd Bergmann 		}
10381c832674SAlban Bedel 	}
10393c53e235SArnd Bergmann 	mutex_unlock(&nvmem_mutex);
10403c53e235SArnd Bergmann 
10413c53e235SArnd Bergmann 	return cell;
10423c53e235SArnd Bergmann }
10433c53e235SArnd Bergmann 
104469aba794SSrinivas Kandagatla /**
104569aba794SSrinivas Kandagatla  * of_nvmem_cell_get() - Get a nvmem cell from given device node and cell id
104669aba794SSrinivas Kandagatla  *
104729143268SVivek Gautam  * @np: Device tree node that uses the nvmem cell.
1048165589f0SBartosz Golaszewski  * @id: nvmem cell name from nvmem-cell-names property, or NULL
1049fd0c478cSVivek Gautam  *      for the cell at index 0 (the lone cell with no accompanying
1050fd0c478cSVivek Gautam  *      nvmem-cell-names property).
105169aba794SSrinivas Kandagatla  *
105269aba794SSrinivas Kandagatla  * Return: Will be an ERR_PTR() on error or a valid pointer
105369aba794SSrinivas Kandagatla  * to a struct nvmem_cell.  The nvmem_cell will be freed by the
105469aba794SSrinivas Kandagatla  * nvmem_cell_put().
105569aba794SSrinivas Kandagatla  */
1056165589f0SBartosz Golaszewski struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *id)
105769aba794SSrinivas Kandagatla {
105869aba794SSrinivas Kandagatla 	struct device_node *cell_np, *nvmem_np;
105969aba794SSrinivas Kandagatla 	struct nvmem_device *nvmem;
1060e888d445SBartosz Golaszewski 	struct nvmem_cell *cell;
1061fd0c478cSVivek Gautam 	int index = 0;
106269aba794SSrinivas Kandagatla 
1063fd0c478cSVivek Gautam 	/* if cell name exists, find index to the name */
1064165589f0SBartosz Golaszewski 	if (id)
1065165589f0SBartosz Golaszewski 		index = of_property_match_string(np, "nvmem-cell-names", id);
106669aba794SSrinivas Kandagatla 
106769aba794SSrinivas Kandagatla 	cell_np = of_parse_phandle(np, "nvmem-cells", index);
106869aba794SSrinivas Kandagatla 	if (!cell_np)
10695087cc19SAlban Bedel 		return ERR_PTR(-ENOENT);
107069aba794SSrinivas Kandagatla 
107169aba794SSrinivas Kandagatla 	nvmem_np = of_get_next_parent(cell_np);
107269aba794SSrinivas Kandagatla 	if (!nvmem_np)
107369aba794SSrinivas Kandagatla 		return ERR_PTR(-EINVAL);
107469aba794SSrinivas Kandagatla 
10758c2a2b8cSThomas Bogendoerfer 	nvmem = __nvmem_device_get(nvmem_np, device_match_of_node);
1076aad8d097SMasahiro Yamada 	of_node_put(nvmem_np);
107769aba794SSrinivas Kandagatla 	if (IS_ERR(nvmem))
107869aba794SSrinivas Kandagatla 		return ERR_CAST(nvmem);
107969aba794SSrinivas Kandagatla 
10800749aa25SSrinivas Kandagatla 	cell = nvmem_find_cell_by_node(nvmem, cell_np);
108169aba794SSrinivas Kandagatla 	if (!cell) {
1082e888d445SBartosz Golaszewski 		__nvmem_device_put(nvmem);
1083e888d445SBartosz Golaszewski 		return ERR_PTR(-ENOENT);
108469aba794SSrinivas Kandagatla 	}
108569aba794SSrinivas Kandagatla 
108669aba794SSrinivas Kandagatla 	return cell;
108769aba794SSrinivas Kandagatla }
108869aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_nvmem_cell_get);
108969aba794SSrinivas Kandagatla #endif
109069aba794SSrinivas Kandagatla 
109169aba794SSrinivas Kandagatla /**
109269aba794SSrinivas Kandagatla  * nvmem_cell_get() - Get nvmem cell of device form a given cell name
109369aba794SSrinivas Kandagatla  *
109429143268SVivek Gautam  * @dev: Device that requests the nvmem cell.
1095165589f0SBartosz Golaszewski  * @id: nvmem cell name to get (this corresponds with the name from the
1096165589f0SBartosz Golaszewski  *      nvmem-cell-names property for DT systems and with the con_id from
1097165589f0SBartosz Golaszewski  *      the lookup entry for non-DT systems).
109869aba794SSrinivas Kandagatla  *
109969aba794SSrinivas Kandagatla  * Return: Will be an ERR_PTR() on error or a valid pointer
110069aba794SSrinivas Kandagatla  * to a struct nvmem_cell.  The nvmem_cell will be freed by the
110169aba794SSrinivas Kandagatla  * nvmem_cell_put().
110269aba794SSrinivas Kandagatla  */
1103165589f0SBartosz Golaszewski struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *id)
110469aba794SSrinivas Kandagatla {
110569aba794SSrinivas Kandagatla 	struct nvmem_cell *cell;
110669aba794SSrinivas Kandagatla 
110769aba794SSrinivas Kandagatla 	if (dev->of_node) { /* try dt first */
1108165589f0SBartosz Golaszewski 		cell = of_nvmem_cell_get(dev->of_node, id);
110969aba794SSrinivas Kandagatla 		if (!IS_ERR(cell) || PTR_ERR(cell) == -EPROBE_DEFER)
111069aba794SSrinivas Kandagatla 			return cell;
111169aba794SSrinivas Kandagatla 	}
111269aba794SSrinivas Kandagatla 
1113165589f0SBartosz Golaszewski 	/* NULL cell id only allowed for device tree; invalid otherwise */
1114165589f0SBartosz Golaszewski 	if (!id)
111587ed1405SDouglas Anderson 		return ERR_PTR(-EINVAL);
111687ed1405SDouglas Anderson 
1117165589f0SBartosz Golaszewski 	return nvmem_cell_get_from_lookup(dev, id);
111869aba794SSrinivas Kandagatla }
111969aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_get);
112069aba794SSrinivas Kandagatla 
112169aba794SSrinivas Kandagatla static void devm_nvmem_cell_release(struct device *dev, void *res)
112269aba794SSrinivas Kandagatla {
112369aba794SSrinivas Kandagatla 	nvmem_cell_put(*(struct nvmem_cell **)res);
112469aba794SSrinivas Kandagatla }
112569aba794SSrinivas Kandagatla 
112669aba794SSrinivas Kandagatla /**
112769aba794SSrinivas Kandagatla  * devm_nvmem_cell_get() - Get nvmem cell of device form a given id
112869aba794SSrinivas Kandagatla  *
112929143268SVivek Gautam  * @dev: Device that requests the nvmem cell.
113029143268SVivek Gautam  * @id: nvmem cell name id to get.
113169aba794SSrinivas Kandagatla  *
113269aba794SSrinivas Kandagatla  * Return: Will be an ERR_PTR() on error or a valid pointer
113369aba794SSrinivas Kandagatla  * to a struct nvmem_cell.  The nvmem_cell will be freed by the
113469aba794SSrinivas Kandagatla  * automatically once the device is freed.
113569aba794SSrinivas Kandagatla  */
113669aba794SSrinivas Kandagatla struct nvmem_cell *devm_nvmem_cell_get(struct device *dev, const char *id)
113769aba794SSrinivas Kandagatla {
113869aba794SSrinivas Kandagatla 	struct nvmem_cell **ptr, *cell;
113969aba794SSrinivas Kandagatla 
114069aba794SSrinivas Kandagatla 	ptr = devres_alloc(devm_nvmem_cell_release, sizeof(*ptr), GFP_KERNEL);
114169aba794SSrinivas Kandagatla 	if (!ptr)
114269aba794SSrinivas Kandagatla 		return ERR_PTR(-ENOMEM);
114369aba794SSrinivas Kandagatla 
114469aba794SSrinivas Kandagatla 	cell = nvmem_cell_get(dev, id);
114569aba794SSrinivas Kandagatla 	if (!IS_ERR(cell)) {
114669aba794SSrinivas Kandagatla 		*ptr = cell;
114769aba794SSrinivas Kandagatla 		devres_add(dev, ptr);
114869aba794SSrinivas Kandagatla 	} else {
114969aba794SSrinivas Kandagatla 		devres_free(ptr);
115069aba794SSrinivas Kandagatla 	}
115169aba794SSrinivas Kandagatla 
115269aba794SSrinivas Kandagatla 	return cell;
115369aba794SSrinivas Kandagatla }
115469aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_cell_get);
115569aba794SSrinivas Kandagatla 
115669aba794SSrinivas Kandagatla static int devm_nvmem_cell_match(struct device *dev, void *res, void *data)
115769aba794SSrinivas Kandagatla {
115869aba794SSrinivas Kandagatla 	struct nvmem_cell **c = res;
115969aba794SSrinivas Kandagatla 
116069aba794SSrinivas Kandagatla 	if (WARN_ON(!c || !*c))
116169aba794SSrinivas Kandagatla 		return 0;
116269aba794SSrinivas Kandagatla 
116369aba794SSrinivas Kandagatla 	return *c == data;
116469aba794SSrinivas Kandagatla }
116569aba794SSrinivas Kandagatla 
116669aba794SSrinivas Kandagatla /**
116769aba794SSrinivas Kandagatla  * devm_nvmem_cell_put() - Release previously allocated nvmem cell
116869aba794SSrinivas Kandagatla  * from devm_nvmem_cell_get.
116969aba794SSrinivas Kandagatla  *
117029143268SVivek Gautam  * @dev: Device that requests the nvmem cell.
117129143268SVivek Gautam  * @cell: Previously allocated nvmem cell by devm_nvmem_cell_get().
117269aba794SSrinivas Kandagatla  */
117369aba794SSrinivas Kandagatla void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell)
117469aba794SSrinivas Kandagatla {
117569aba794SSrinivas Kandagatla 	int ret;
117669aba794SSrinivas Kandagatla 
117769aba794SSrinivas Kandagatla 	ret = devres_release(dev, devm_nvmem_cell_release,
117869aba794SSrinivas Kandagatla 				devm_nvmem_cell_match, cell);
117969aba794SSrinivas Kandagatla 
118069aba794SSrinivas Kandagatla 	WARN_ON(ret);
118169aba794SSrinivas Kandagatla }
118269aba794SSrinivas Kandagatla EXPORT_SYMBOL(devm_nvmem_cell_put);
118369aba794SSrinivas Kandagatla 
118469aba794SSrinivas Kandagatla /**
118569aba794SSrinivas Kandagatla  * nvmem_cell_put() - Release previously allocated nvmem cell.
118669aba794SSrinivas Kandagatla  *
118729143268SVivek Gautam  * @cell: Previously allocated nvmem cell by nvmem_cell_get().
118869aba794SSrinivas Kandagatla  */
118969aba794SSrinivas Kandagatla void nvmem_cell_put(struct nvmem_cell *cell)
119069aba794SSrinivas Kandagatla {
119169aba794SSrinivas Kandagatla 	struct nvmem_device *nvmem = cell->nvmem;
119269aba794SSrinivas Kandagatla 
119369aba794SSrinivas Kandagatla 	__nvmem_device_put(nvmem);
119469aba794SSrinivas Kandagatla }
119569aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_put);
119669aba794SSrinivas Kandagatla 
1197f7c04f16SMasahiro Yamada static void nvmem_shift_read_buffer_in_place(struct nvmem_cell *cell, void *buf)
119869aba794SSrinivas Kandagatla {
119969aba794SSrinivas Kandagatla 	u8 *p, *b;
12002fe518feSJorge Ramirez-Ortiz 	int i, extra, bit_offset = cell->bit_offset;
120169aba794SSrinivas Kandagatla 
120269aba794SSrinivas Kandagatla 	p = b = buf;
120369aba794SSrinivas Kandagatla 	if (bit_offset) {
120469aba794SSrinivas Kandagatla 		/* First shift */
120569aba794SSrinivas Kandagatla 		*b++ >>= bit_offset;
120669aba794SSrinivas Kandagatla 
120769aba794SSrinivas Kandagatla 		/* setup rest of the bytes if any */
120869aba794SSrinivas Kandagatla 		for (i = 1; i < cell->bytes; i++) {
120969aba794SSrinivas Kandagatla 			/* Get bits from next byte and shift them towards msb */
121069aba794SSrinivas Kandagatla 			*p |= *b << (BITS_PER_BYTE - bit_offset);
121169aba794SSrinivas Kandagatla 
121269aba794SSrinivas Kandagatla 			p = b;
121369aba794SSrinivas Kandagatla 			*b++ >>= bit_offset;
121469aba794SSrinivas Kandagatla 		}
12152fe518feSJorge Ramirez-Ortiz 	} else {
12162fe518feSJorge Ramirez-Ortiz 		/* point to the msb */
12172fe518feSJorge Ramirez-Ortiz 		p += cell->bytes - 1;
12182fe518feSJorge Ramirez-Ortiz 	}
121969aba794SSrinivas Kandagatla 
122069aba794SSrinivas Kandagatla 	/* result fits in less bytes */
12212fe518feSJorge Ramirez-Ortiz 	extra = cell->bytes - DIV_ROUND_UP(cell->nbits, BITS_PER_BYTE);
12222fe518feSJorge Ramirez-Ortiz 	while (--extra >= 0)
122369aba794SSrinivas Kandagatla 		*p-- = 0;
12242fe518feSJorge Ramirez-Ortiz 
122569aba794SSrinivas Kandagatla 	/* clear msb bits if any leftover in the last byte */
122669aba794SSrinivas Kandagatla 	*p &= GENMASK((cell->nbits%BITS_PER_BYTE) - 1, 0);
122769aba794SSrinivas Kandagatla }
122869aba794SSrinivas Kandagatla 
122969aba794SSrinivas Kandagatla static int __nvmem_cell_read(struct nvmem_device *nvmem,
123069aba794SSrinivas Kandagatla 		      struct nvmem_cell *cell,
123169aba794SSrinivas Kandagatla 		      void *buf, size_t *len)
123269aba794SSrinivas Kandagatla {
123369aba794SSrinivas Kandagatla 	int rc;
123469aba794SSrinivas Kandagatla 
1235795ddd18SSrinivas Kandagatla 	rc = nvmem_reg_read(nvmem, cell->offset, buf, cell->bytes);
123669aba794SSrinivas Kandagatla 
1237287980e4SArnd Bergmann 	if (rc)
123869aba794SSrinivas Kandagatla 		return rc;
123969aba794SSrinivas Kandagatla 
124069aba794SSrinivas Kandagatla 	/* shift bits in-place */
1241cbf854abSAxel Lin 	if (cell->bit_offset || cell->nbits)
124269aba794SSrinivas Kandagatla 		nvmem_shift_read_buffer_in_place(cell, buf);
124369aba794SSrinivas Kandagatla 
12443b4a6877SVivek Gautam 	if (len)
124569aba794SSrinivas Kandagatla 		*len = cell->bytes;
124669aba794SSrinivas Kandagatla 
124769aba794SSrinivas Kandagatla 	return 0;
124869aba794SSrinivas Kandagatla }
124969aba794SSrinivas Kandagatla 
125069aba794SSrinivas Kandagatla /**
125169aba794SSrinivas Kandagatla  * nvmem_cell_read() - Read a given nvmem cell
125269aba794SSrinivas Kandagatla  *
125369aba794SSrinivas Kandagatla  * @cell: nvmem cell to be read.
12543b4a6877SVivek Gautam  * @len: pointer to length of cell which will be populated on successful read;
12553b4a6877SVivek Gautam  *	 can be NULL.
125669aba794SSrinivas Kandagatla  *
1257b577fafcSBrian Norris  * Return: ERR_PTR() on error or a valid pointer to a buffer on success. The
1258b577fafcSBrian Norris  * buffer should be freed by the consumer with a kfree().
125969aba794SSrinivas Kandagatla  */
126069aba794SSrinivas Kandagatla void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len)
126169aba794SSrinivas Kandagatla {
126269aba794SSrinivas Kandagatla 	struct nvmem_device *nvmem = cell->nvmem;
126369aba794SSrinivas Kandagatla 	u8 *buf;
126469aba794SSrinivas Kandagatla 	int rc;
126569aba794SSrinivas Kandagatla 
1266795ddd18SSrinivas Kandagatla 	if (!nvmem)
126769aba794SSrinivas Kandagatla 		return ERR_PTR(-EINVAL);
126869aba794SSrinivas Kandagatla 
126969aba794SSrinivas Kandagatla 	buf = kzalloc(cell->bytes, GFP_KERNEL);
127069aba794SSrinivas Kandagatla 	if (!buf)
127169aba794SSrinivas Kandagatla 		return ERR_PTR(-ENOMEM);
127269aba794SSrinivas Kandagatla 
127369aba794SSrinivas Kandagatla 	rc = __nvmem_cell_read(nvmem, cell, buf, len);
1274287980e4SArnd Bergmann 	if (rc) {
127569aba794SSrinivas Kandagatla 		kfree(buf);
127669aba794SSrinivas Kandagatla 		return ERR_PTR(rc);
127769aba794SSrinivas Kandagatla 	}
127869aba794SSrinivas Kandagatla 
127969aba794SSrinivas Kandagatla 	return buf;
128069aba794SSrinivas Kandagatla }
128169aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_read);
128269aba794SSrinivas Kandagatla 
1283f7c04f16SMasahiro Yamada static void *nvmem_cell_prepare_write_buffer(struct nvmem_cell *cell,
128469aba794SSrinivas Kandagatla 					     u8 *_buf, int len)
128569aba794SSrinivas Kandagatla {
128669aba794SSrinivas Kandagatla 	struct nvmem_device *nvmem = cell->nvmem;
128769aba794SSrinivas Kandagatla 	int i, rc, nbits, bit_offset = cell->bit_offset;
128869aba794SSrinivas Kandagatla 	u8 v, *p, *buf, *b, pbyte, pbits;
128969aba794SSrinivas Kandagatla 
129069aba794SSrinivas Kandagatla 	nbits = cell->nbits;
129169aba794SSrinivas Kandagatla 	buf = kzalloc(cell->bytes, GFP_KERNEL);
129269aba794SSrinivas Kandagatla 	if (!buf)
129369aba794SSrinivas Kandagatla 		return ERR_PTR(-ENOMEM);
129469aba794SSrinivas Kandagatla 
129569aba794SSrinivas Kandagatla 	memcpy(buf, _buf, len);
129669aba794SSrinivas Kandagatla 	p = b = buf;
129769aba794SSrinivas Kandagatla 
129869aba794SSrinivas Kandagatla 	if (bit_offset) {
129969aba794SSrinivas Kandagatla 		pbyte = *b;
130069aba794SSrinivas Kandagatla 		*b <<= bit_offset;
130169aba794SSrinivas Kandagatla 
130269aba794SSrinivas Kandagatla 		/* setup the first byte with lsb bits from nvmem */
1303795ddd18SSrinivas Kandagatla 		rc = nvmem_reg_read(nvmem, cell->offset, &v, 1);
130450808bfcSMathieu Malaterre 		if (rc)
130550808bfcSMathieu Malaterre 			goto err;
130669aba794SSrinivas Kandagatla 		*b++ |= GENMASK(bit_offset - 1, 0) & v;
130769aba794SSrinivas Kandagatla 
130869aba794SSrinivas Kandagatla 		/* setup rest of the byte if any */
130969aba794SSrinivas Kandagatla 		for (i = 1; i < cell->bytes; i++) {
131069aba794SSrinivas Kandagatla 			/* Get last byte bits and shift them towards lsb */
131169aba794SSrinivas Kandagatla 			pbits = pbyte >> (BITS_PER_BYTE - 1 - bit_offset);
131269aba794SSrinivas Kandagatla 			pbyte = *b;
131369aba794SSrinivas Kandagatla 			p = b;
131469aba794SSrinivas Kandagatla 			*b <<= bit_offset;
131569aba794SSrinivas Kandagatla 			*b++ |= pbits;
131669aba794SSrinivas Kandagatla 		}
131769aba794SSrinivas Kandagatla 	}
131869aba794SSrinivas Kandagatla 
131969aba794SSrinivas Kandagatla 	/* if it's not end on byte boundary */
132069aba794SSrinivas Kandagatla 	if ((nbits + bit_offset) % BITS_PER_BYTE) {
132169aba794SSrinivas Kandagatla 		/* setup the last byte with msb bits from nvmem */
1322795ddd18SSrinivas Kandagatla 		rc = nvmem_reg_read(nvmem,
132369aba794SSrinivas Kandagatla 				    cell->offset + cell->bytes - 1, &v, 1);
132450808bfcSMathieu Malaterre 		if (rc)
132550808bfcSMathieu Malaterre 			goto err;
132669aba794SSrinivas Kandagatla 		*p |= GENMASK(7, (nbits + bit_offset) % BITS_PER_BYTE) & v;
132769aba794SSrinivas Kandagatla 
132869aba794SSrinivas Kandagatla 	}
132969aba794SSrinivas Kandagatla 
133069aba794SSrinivas Kandagatla 	return buf;
133150808bfcSMathieu Malaterre err:
133250808bfcSMathieu Malaterre 	kfree(buf);
133350808bfcSMathieu Malaterre 	return ERR_PTR(rc);
133469aba794SSrinivas Kandagatla }
133569aba794SSrinivas Kandagatla 
133669aba794SSrinivas Kandagatla /**
133769aba794SSrinivas Kandagatla  * nvmem_cell_write() - Write to a given nvmem cell
133869aba794SSrinivas Kandagatla  *
133969aba794SSrinivas Kandagatla  * @cell: nvmem cell to be written.
134069aba794SSrinivas Kandagatla  * @buf: Buffer to be written.
134169aba794SSrinivas Kandagatla  * @len: length of buffer to be written to nvmem cell.
134269aba794SSrinivas Kandagatla  *
134369aba794SSrinivas Kandagatla  * Return: length of bytes written or negative on failure.
134469aba794SSrinivas Kandagatla  */
134569aba794SSrinivas Kandagatla int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len)
134669aba794SSrinivas Kandagatla {
134769aba794SSrinivas Kandagatla 	struct nvmem_device *nvmem = cell->nvmem;
134869aba794SSrinivas Kandagatla 	int rc;
134969aba794SSrinivas Kandagatla 
1350795ddd18SSrinivas Kandagatla 	if (!nvmem || nvmem->read_only ||
135169aba794SSrinivas Kandagatla 	    (cell->bit_offset == 0 && len != cell->bytes))
135269aba794SSrinivas Kandagatla 		return -EINVAL;
135369aba794SSrinivas Kandagatla 
135469aba794SSrinivas Kandagatla 	if (cell->bit_offset || cell->nbits) {
135569aba794SSrinivas Kandagatla 		buf = nvmem_cell_prepare_write_buffer(cell, buf, len);
135669aba794SSrinivas Kandagatla 		if (IS_ERR(buf))
135769aba794SSrinivas Kandagatla 			return PTR_ERR(buf);
135869aba794SSrinivas Kandagatla 	}
135969aba794SSrinivas Kandagatla 
1360795ddd18SSrinivas Kandagatla 	rc = nvmem_reg_write(nvmem, cell->offset, buf, cell->bytes);
136169aba794SSrinivas Kandagatla 
136269aba794SSrinivas Kandagatla 	/* free the tmp buffer */
1363ace22170SAxel Lin 	if (cell->bit_offset || cell->nbits)
136469aba794SSrinivas Kandagatla 		kfree(buf);
136569aba794SSrinivas Kandagatla 
1366287980e4SArnd Bergmann 	if (rc)
136769aba794SSrinivas Kandagatla 		return rc;
136869aba794SSrinivas Kandagatla 
136969aba794SSrinivas Kandagatla 	return len;
137069aba794SSrinivas Kandagatla }
137169aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_write);
137269aba794SSrinivas Kandagatla 
13736bb317ceSYangtao Li static int nvmem_cell_read_common(struct device *dev, const char *cell_id,
13746bb317ceSYangtao Li 				  void *val, size_t count)
13750a9b2d1cSFabrice Gasnier {
13760a9b2d1cSFabrice Gasnier 	struct nvmem_cell *cell;
13770a9b2d1cSFabrice Gasnier 	void *buf;
13780a9b2d1cSFabrice Gasnier 	size_t len;
13790a9b2d1cSFabrice Gasnier 
13800a9b2d1cSFabrice Gasnier 	cell = nvmem_cell_get(dev, cell_id);
13810a9b2d1cSFabrice Gasnier 	if (IS_ERR(cell))
13820a9b2d1cSFabrice Gasnier 		return PTR_ERR(cell);
13830a9b2d1cSFabrice Gasnier 
13840a9b2d1cSFabrice Gasnier 	buf = nvmem_cell_read(cell, &len);
13850a9b2d1cSFabrice Gasnier 	if (IS_ERR(buf)) {
13860a9b2d1cSFabrice Gasnier 		nvmem_cell_put(cell);
13870a9b2d1cSFabrice Gasnier 		return PTR_ERR(buf);
13880a9b2d1cSFabrice Gasnier 	}
13896bb317ceSYangtao Li 	if (len != count) {
13900a9b2d1cSFabrice Gasnier 		kfree(buf);
13910a9b2d1cSFabrice Gasnier 		nvmem_cell_put(cell);
13920a9b2d1cSFabrice Gasnier 		return -EINVAL;
13930a9b2d1cSFabrice Gasnier 	}
13946bb317ceSYangtao Li 	memcpy(val, buf, count);
13950a9b2d1cSFabrice Gasnier 	kfree(buf);
13960a9b2d1cSFabrice Gasnier 	nvmem_cell_put(cell);
13970a9b2d1cSFabrice Gasnier 
13980a9b2d1cSFabrice Gasnier 	return 0;
13990a9b2d1cSFabrice Gasnier }
14006bb317ceSYangtao Li 
14016bb317ceSYangtao Li /**
14025037d368SAndreas Färber  * nvmem_cell_read_u8() - Read a cell value as a u8
14035037d368SAndreas Färber  *
14045037d368SAndreas Färber  * @dev: Device that requests the nvmem cell.
14055037d368SAndreas Färber  * @cell_id: Name of nvmem cell to read.
14065037d368SAndreas Färber  * @val: pointer to output value.
14075037d368SAndreas Färber  *
14085037d368SAndreas Färber  * Return: 0 on success or negative errno.
14095037d368SAndreas Färber  */
14105037d368SAndreas Färber int nvmem_cell_read_u8(struct device *dev, const char *cell_id, u8 *val)
14115037d368SAndreas Färber {
14125037d368SAndreas Färber 	return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val));
14135037d368SAndreas Färber }
14145037d368SAndreas Färber EXPORT_SYMBOL_GPL(nvmem_cell_read_u8);
14155037d368SAndreas Färber 
14165037d368SAndreas Färber /**
14173a758071SAndreas Färber  * nvmem_cell_read_u16() - Read a cell value as a u16
14186bb317ceSYangtao Li  *
14196bb317ceSYangtao Li  * @dev: Device that requests the nvmem cell.
14206bb317ceSYangtao Li  * @cell_id: Name of nvmem cell to read.
14216bb317ceSYangtao Li  * @val: pointer to output value.
14226bb317ceSYangtao Li  *
14236bb317ceSYangtao Li  * Return: 0 on success or negative errno.
14246bb317ceSYangtao Li  */
14256bb317ceSYangtao Li int nvmem_cell_read_u16(struct device *dev, const char *cell_id, u16 *val)
14266bb317ceSYangtao Li {
14276bb317ceSYangtao Li 	return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val));
14286bb317ceSYangtao Li }
14290a9b2d1cSFabrice Gasnier EXPORT_SYMBOL_GPL(nvmem_cell_read_u16);
14300a9b2d1cSFabrice Gasnier 
14310a9b2d1cSFabrice Gasnier /**
14323a758071SAndreas Färber  * nvmem_cell_read_u32() - Read a cell value as a u32
1433d026d70aSLeonard Crestez  *
1434d026d70aSLeonard Crestez  * @dev: Device that requests the nvmem cell.
1435d026d70aSLeonard Crestez  * @cell_id: Name of nvmem cell to read.
1436d026d70aSLeonard Crestez  * @val: pointer to output value.
1437d026d70aSLeonard Crestez  *
1438d026d70aSLeonard Crestez  * Return: 0 on success or negative errno.
1439d026d70aSLeonard Crestez  */
1440d026d70aSLeonard Crestez int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val)
1441d026d70aSLeonard Crestez {
14426bb317ceSYangtao Li 	return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val));
1443d026d70aSLeonard Crestez }
1444d026d70aSLeonard Crestez EXPORT_SYMBOL_GPL(nvmem_cell_read_u32);
1445d026d70aSLeonard Crestez 
1446d026d70aSLeonard Crestez /**
14473a758071SAndreas Färber  * nvmem_cell_read_u64() - Read a cell value as a u64
14488b977c54SYangtao Li  *
14498b977c54SYangtao Li  * @dev: Device that requests the nvmem cell.
14508b977c54SYangtao Li  * @cell_id: Name of nvmem cell to read.
14518b977c54SYangtao Li  * @val: pointer to output value.
14528b977c54SYangtao Li  *
14538b977c54SYangtao Li  * Return: 0 on success or negative errno.
14548b977c54SYangtao Li  */
14558b977c54SYangtao Li int nvmem_cell_read_u64(struct device *dev, const char *cell_id, u64 *val)
14568b977c54SYangtao Li {
14578b977c54SYangtao Li 	return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val));
14588b977c54SYangtao Li }
14598b977c54SYangtao Li EXPORT_SYMBOL_GPL(nvmem_cell_read_u64);
14608b977c54SYangtao Li 
14618b977c54SYangtao Li /**
1462e2a5402eSSrinivas Kandagatla  * nvmem_device_cell_read() - Read a given nvmem device and cell
1463e2a5402eSSrinivas Kandagatla  *
1464e2a5402eSSrinivas Kandagatla  * @nvmem: nvmem device to read from.
1465e2a5402eSSrinivas Kandagatla  * @info: nvmem cell info to be read.
1466e2a5402eSSrinivas Kandagatla  * @buf: buffer pointer which will be populated on successful read.
1467e2a5402eSSrinivas Kandagatla  *
1468e2a5402eSSrinivas Kandagatla  * Return: length of successful bytes read on success and negative
1469e2a5402eSSrinivas Kandagatla  * error code on error.
1470e2a5402eSSrinivas Kandagatla  */
1471e2a5402eSSrinivas Kandagatla ssize_t nvmem_device_cell_read(struct nvmem_device *nvmem,
1472e2a5402eSSrinivas Kandagatla 			   struct nvmem_cell_info *info, void *buf)
1473e2a5402eSSrinivas Kandagatla {
1474e2a5402eSSrinivas Kandagatla 	struct nvmem_cell cell;
1475e2a5402eSSrinivas Kandagatla 	int rc;
1476e2a5402eSSrinivas Kandagatla 	ssize_t len;
1477e2a5402eSSrinivas Kandagatla 
1478795ddd18SSrinivas Kandagatla 	if (!nvmem)
1479e2a5402eSSrinivas Kandagatla 		return -EINVAL;
1480e2a5402eSSrinivas Kandagatla 
1481*fc9eec4dSVadym Kochan 	rc = nvmem_cell_info_to_nvmem_cell_nodup(nvmem, info, &cell);
1482287980e4SArnd Bergmann 	if (rc)
1483e2a5402eSSrinivas Kandagatla 		return rc;
1484e2a5402eSSrinivas Kandagatla 
1485e2a5402eSSrinivas Kandagatla 	rc = __nvmem_cell_read(nvmem, &cell, buf, &len);
1486287980e4SArnd Bergmann 	if (rc)
1487e2a5402eSSrinivas Kandagatla 		return rc;
1488e2a5402eSSrinivas Kandagatla 
1489e2a5402eSSrinivas Kandagatla 	return len;
1490e2a5402eSSrinivas Kandagatla }
1491e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_cell_read);
1492e2a5402eSSrinivas Kandagatla 
1493e2a5402eSSrinivas Kandagatla /**
1494e2a5402eSSrinivas Kandagatla  * nvmem_device_cell_write() - Write cell to a given nvmem device
1495e2a5402eSSrinivas Kandagatla  *
1496e2a5402eSSrinivas Kandagatla  * @nvmem: nvmem device to be written to.
149729143268SVivek Gautam  * @info: nvmem cell info to be written.
1498e2a5402eSSrinivas Kandagatla  * @buf: buffer to be written to cell.
1499e2a5402eSSrinivas Kandagatla  *
1500e2a5402eSSrinivas Kandagatla  * Return: length of bytes written or negative error code on failure.
150148f63a2cSBartosz Golaszewski  */
1502e2a5402eSSrinivas Kandagatla int nvmem_device_cell_write(struct nvmem_device *nvmem,
1503e2a5402eSSrinivas Kandagatla 			    struct nvmem_cell_info *info, void *buf)
1504e2a5402eSSrinivas Kandagatla {
1505e2a5402eSSrinivas Kandagatla 	struct nvmem_cell cell;
1506e2a5402eSSrinivas Kandagatla 	int rc;
1507e2a5402eSSrinivas Kandagatla 
1508795ddd18SSrinivas Kandagatla 	if (!nvmem)
1509e2a5402eSSrinivas Kandagatla 		return -EINVAL;
1510e2a5402eSSrinivas Kandagatla 
1511*fc9eec4dSVadym Kochan 	rc = nvmem_cell_info_to_nvmem_cell_nodup(nvmem, info, &cell);
1512287980e4SArnd Bergmann 	if (rc)
1513e2a5402eSSrinivas Kandagatla 		return rc;
1514e2a5402eSSrinivas Kandagatla 
1515e2a5402eSSrinivas Kandagatla 	return nvmem_cell_write(&cell, buf, cell.bytes);
1516e2a5402eSSrinivas Kandagatla }
1517e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_cell_write);
1518e2a5402eSSrinivas Kandagatla 
1519e2a5402eSSrinivas Kandagatla /**
1520e2a5402eSSrinivas Kandagatla  * nvmem_device_read() - Read from a given nvmem device
1521e2a5402eSSrinivas Kandagatla  *
1522e2a5402eSSrinivas Kandagatla  * @nvmem: nvmem device to read from.
1523e2a5402eSSrinivas Kandagatla  * @offset: offset in nvmem device.
1524e2a5402eSSrinivas Kandagatla  * @bytes: number of bytes to read.
1525e2a5402eSSrinivas Kandagatla  * @buf: buffer pointer which will be populated on successful read.
1526e2a5402eSSrinivas Kandagatla  *
1527e2a5402eSSrinivas Kandagatla  * Return: length of successful bytes read on success and negative
1528e2a5402eSSrinivas Kandagatla  * error code on error.
1529e2a5402eSSrinivas Kandagatla  */
1530e2a5402eSSrinivas Kandagatla int nvmem_device_read(struct nvmem_device *nvmem,
1531e2a5402eSSrinivas Kandagatla 		      unsigned int offset,
1532e2a5402eSSrinivas Kandagatla 		      size_t bytes, void *buf)
1533e2a5402eSSrinivas Kandagatla {
1534e2a5402eSSrinivas Kandagatla 	int rc;
1535e2a5402eSSrinivas Kandagatla 
1536795ddd18SSrinivas Kandagatla 	if (!nvmem)
1537e2a5402eSSrinivas Kandagatla 		return -EINVAL;
1538e2a5402eSSrinivas Kandagatla 
1539795ddd18SSrinivas Kandagatla 	rc = nvmem_reg_read(nvmem, offset, buf, bytes);
1540e2a5402eSSrinivas Kandagatla 
1541287980e4SArnd Bergmann 	if (rc)
1542e2a5402eSSrinivas Kandagatla 		return rc;
1543e2a5402eSSrinivas Kandagatla 
1544e2a5402eSSrinivas Kandagatla 	return bytes;
1545e2a5402eSSrinivas Kandagatla }
1546e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_read);
1547e2a5402eSSrinivas Kandagatla 
1548e2a5402eSSrinivas Kandagatla /**
1549e2a5402eSSrinivas Kandagatla  * nvmem_device_write() - Write cell to a given nvmem device
1550e2a5402eSSrinivas Kandagatla  *
1551e2a5402eSSrinivas Kandagatla  * @nvmem: nvmem device to be written to.
1552e2a5402eSSrinivas Kandagatla  * @offset: offset in nvmem device.
1553e2a5402eSSrinivas Kandagatla  * @bytes: number of bytes to write.
1554e2a5402eSSrinivas Kandagatla  * @buf: buffer to be written.
1555e2a5402eSSrinivas Kandagatla  *
1556e2a5402eSSrinivas Kandagatla  * Return: length of bytes written or negative error code on failure.
155748f63a2cSBartosz Golaszewski  */
1558e2a5402eSSrinivas Kandagatla int nvmem_device_write(struct nvmem_device *nvmem,
1559e2a5402eSSrinivas Kandagatla 		       unsigned int offset,
1560e2a5402eSSrinivas Kandagatla 		       size_t bytes, void *buf)
1561e2a5402eSSrinivas Kandagatla {
1562e2a5402eSSrinivas Kandagatla 	int rc;
1563e2a5402eSSrinivas Kandagatla 
1564795ddd18SSrinivas Kandagatla 	if (!nvmem)
1565e2a5402eSSrinivas Kandagatla 		return -EINVAL;
1566e2a5402eSSrinivas Kandagatla 
1567795ddd18SSrinivas Kandagatla 	rc = nvmem_reg_write(nvmem, offset, buf, bytes);
1568e2a5402eSSrinivas Kandagatla 
1569287980e4SArnd Bergmann 	if (rc)
1570e2a5402eSSrinivas Kandagatla 		return rc;
1571e2a5402eSSrinivas Kandagatla 
1572e2a5402eSSrinivas Kandagatla 
1573e2a5402eSSrinivas Kandagatla 	return bytes;
1574e2a5402eSSrinivas Kandagatla }
1575e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_write);
1576e2a5402eSSrinivas Kandagatla 
1577d7b9fd16SBartosz Golaszewski /**
1578b985f4cbSBartosz Golaszewski  * nvmem_add_cell_table() - register a table of cell info entries
1579b985f4cbSBartosz Golaszewski  *
1580b985f4cbSBartosz Golaszewski  * @table: table of cell info entries
1581b985f4cbSBartosz Golaszewski  */
1582b985f4cbSBartosz Golaszewski void nvmem_add_cell_table(struct nvmem_cell_table *table)
1583b985f4cbSBartosz Golaszewski {
1584b985f4cbSBartosz Golaszewski 	mutex_lock(&nvmem_cell_mutex);
1585b985f4cbSBartosz Golaszewski 	list_add_tail(&table->node, &nvmem_cell_tables);
1586b985f4cbSBartosz Golaszewski 	mutex_unlock(&nvmem_cell_mutex);
1587b985f4cbSBartosz Golaszewski }
1588b985f4cbSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_add_cell_table);
1589b985f4cbSBartosz Golaszewski 
1590b985f4cbSBartosz Golaszewski /**
1591b985f4cbSBartosz Golaszewski  * nvmem_del_cell_table() - remove a previously registered cell info table
1592b985f4cbSBartosz Golaszewski  *
1593b985f4cbSBartosz Golaszewski  * @table: table of cell info entries
1594b985f4cbSBartosz Golaszewski  */
1595b985f4cbSBartosz Golaszewski void nvmem_del_cell_table(struct nvmem_cell_table *table)
1596b985f4cbSBartosz Golaszewski {
1597b985f4cbSBartosz Golaszewski 	mutex_lock(&nvmem_cell_mutex);
1598b985f4cbSBartosz Golaszewski 	list_del(&table->node);
1599b985f4cbSBartosz Golaszewski 	mutex_unlock(&nvmem_cell_mutex);
1600b985f4cbSBartosz Golaszewski }
1601b985f4cbSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_del_cell_table);
1602b985f4cbSBartosz Golaszewski 
1603b985f4cbSBartosz Golaszewski /**
1604506157beSBartosz Golaszewski  * nvmem_add_cell_lookups() - register a list of cell lookup entries
1605506157beSBartosz Golaszewski  *
1606506157beSBartosz Golaszewski  * @entries: array of cell lookup entries
1607506157beSBartosz Golaszewski  * @nentries: number of cell lookup entries in the array
1608506157beSBartosz Golaszewski  */
1609506157beSBartosz Golaszewski void nvmem_add_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries)
1610506157beSBartosz Golaszewski {
1611506157beSBartosz Golaszewski 	int i;
1612506157beSBartosz Golaszewski 
1613506157beSBartosz Golaszewski 	mutex_lock(&nvmem_lookup_mutex);
1614506157beSBartosz Golaszewski 	for (i = 0; i < nentries; i++)
1615506157beSBartosz Golaszewski 		list_add_tail(&entries[i].node, &nvmem_lookup_list);
1616506157beSBartosz Golaszewski 	mutex_unlock(&nvmem_lookup_mutex);
1617506157beSBartosz Golaszewski }
1618506157beSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_add_cell_lookups);
1619506157beSBartosz Golaszewski 
1620506157beSBartosz Golaszewski /**
1621506157beSBartosz Golaszewski  * nvmem_del_cell_lookups() - remove a list of previously added cell lookup
1622506157beSBartosz Golaszewski  *                            entries
1623506157beSBartosz Golaszewski  *
1624506157beSBartosz Golaszewski  * @entries: array of cell lookup entries
1625506157beSBartosz Golaszewski  * @nentries: number of cell lookup entries in the array
1626506157beSBartosz Golaszewski  */
1627506157beSBartosz Golaszewski void nvmem_del_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries)
1628506157beSBartosz Golaszewski {
1629506157beSBartosz Golaszewski 	int i;
1630506157beSBartosz Golaszewski 
1631506157beSBartosz Golaszewski 	mutex_lock(&nvmem_lookup_mutex);
1632506157beSBartosz Golaszewski 	for (i = 0; i < nentries; i++)
1633506157beSBartosz Golaszewski 		list_del(&entries[i].node);
1634506157beSBartosz Golaszewski 	mutex_unlock(&nvmem_lookup_mutex);
1635506157beSBartosz Golaszewski }
1636506157beSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_del_cell_lookups);
1637506157beSBartosz Golaszewski 
1638506157beSBartosz Golaszewski /**
1639d7b9fd16SBartosz Golaszewski  * nvmem_dev_name() - Get the name of a given nvmem device.
1640d7b9fd16SBartosz Golaszewski  *
1641d7b9fd16SBartosz Golaszewski  * @nvmem: nvmem device.
1642d7b9fd16SBartosz Golaszewski  *
1643d7b9fd16SBartosz Golaszewski  * Return: name of the nvmem device.
1644d7b9fd16SBartosz Golaszewski  */
1645d7b9fd16SBartosz Golaszewski const char *nvmem_dev_name(struct nvmem_device *nvmem)
1646d7b9fd16SBartosz Golaszewski {
1647d7b9fd16SBartosz Golaszewski 	return dev_name(&nvmem->dev);
1648d7b9fd16SBartosz Golaszewski }
1649d7b9fd16SBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_dev_name);
1650d7b9fd16SBartosz Golaszewski 
1651eace75cfSSrinivas Kandagatla static int __init nvmem_init(void)
1652eace75cfSSrinivas Kandagatla {
1653eace75cfSSrinivas Kandagatla 	return bus_register(&nvmem_bus_type);
1654eace75cfSSrinivas Kandagatla }
1655eace75cfSSrinivas Kandagatla 
1656eace75cfSSrinivas Kandagatla static void __exit nvmem_exit(void)
1657eace75cfSSrinivas Kandagatla {
1658eace75cfSSrinivas Kandagatla 	bus_unregister(&nvmem_bus_type);
1659eace75cfSSrinivas Kandagatla }
1660eace75cfSSrinivas Kandagatla 
1661eace75cfSSrinivas Kandagatla subsys_initcall(nvmem_init);
1662eace75cfSSrinivas Kandagatla module_exit(nvmem_exit);
1663eace75cfSSrinivas Kandagatla 
1664eace75cfSSrinivas Kandagatla MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org");
1665eace75cfSSrinivas Kandagatla MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com");
1666eace75cfSSrinivas Kandagatla MODULE_DESCRIPTION("nvmem Driver Core");
1667eace75cfSSrinivas Kandagatla MODULE_LICENSE("GPL v2");
1668