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