1b1c1db98SBartosz Golaszewski // SPDX-License-Identifier: GPL-2.0 2eace75cfSSrinivas Kandagatla /* 3eace75cfSSrinivas Kandagatla * nvmem framework core. 4eace75cfSSrinivas Kandagatla * 5eace75cfSSrinivas Kandagatla * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org> 6eace75cfSSrinivas Kandagatla * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com> 7eace75cfSSrinivas Kandagatla */ 8eace75cfSSrinivas Kandagatla 9eace75cfSSrinivas Kandagatla #include <linux/device.h> 10eace75cfSSrinivas Kandagatla #include <linux/export.h> 11eace75cfSSrinivas Kandagatla #include <linux/fs.h> 12eace75cfSSrinivas Kandagatla #include <linux/idr.h> 13eace75cfSSrinivas Kandagatla #include <linux/init.h> 14c1de7f43SBartosz Golaszewski #include <linux/kref.h> 15eace75cfSSrinivas Kandagatla #include <linux/module.h> 16eace75cfSSrinivas Kandagatla #include <linux/nvmem-consumer.h> 17eace75cfSSrinivas Kandagatla #include <linux/nvmem-provider.h> 182a127da4SKhouloud Touil #include <linux/gpio/consumer.h> 19eace75cfSSrinivas Kandagatla #include <linux/of.h> 20eace75cfSSrinivas Kandagatla #include <linux/slab.h> 2184400305SSrinivas Kandagatla 2284400305SSrinivas Kandagatla struct nvmem_device { 2384400305SSrinivas Kandagatla struct module *owner; 2484400305SSrinivas Kandagatla struct device dev; 2584400305SSrinivas Kandagatla int stride; 2684400305SSrinivas Kandagatla int word_size; 2784400305SSrinivas Kandagatla int id; 2884400305SSrinivas Kandagatla struct kref refcnt; 2984400305SSrinivas Kandagatla size_t size; 3084400305SSrinivas Kandagatla bool read_only; 3184400305SSrinivas Kandagatla bool root_only; 3284400305SSrinivas Kandagatla int flags; 3384400305SSrinivas Kandagatla enum nvmem_type type; 3484400305SSrinivas Kandagatla struct bin_attribute eeprom; 3584400305SSrinivas Kandagatla struct device *base_dev; 3684400305SSrinivas Kandagatla struct list_head cells; 37fd3bb8f5SEvan Green const struct nvmem_keepout *keepout; 38fd3bb8f5SEvan Green unsigned int nkeepout; 3984400305SSrinivas Kandagatla nvmem_reg_read_t reg_read; 4084400305SSrinivas Kandagatla nvmem_reg_write_t reg_write; 4184400305SSrinivas Kandagatla struct gpio_desc *wp_gpio; 42266570f4SMichael Walle struct nvmem_layout *layout; 4384400305SSrinivas Kandagatla void *priv; 4484400305SSrinivas Kandagatla }; 4584400305SSrinivas Kandagatla 4684400305SSrinivas Kandagatla #define to_nvmem_device(d) container_of(d, struct nvmem_device, dev) 4784400305SSrinivas Kandagatla 4884400305SSrinivas Kandagatla #define FLAG_COMPAT BIT(0) 497ae6478bSSrinivas Kandagatla struct nvmem_cell_entry { 50eace75cfSSrinivas Kandagatla const char *name; 51eace75cfSSrinivas Kandagatla int offset; 5255d4980cSRafał Miłecki size_t raw_len; 53eace75cfSSrinivas Kandagatla int bytes; 54eace75cfSSrinivas Kandagatla int bit_offset; 55eace75cfSSrinivas Kandagatla int nbits; 56345ec382SMichael Walle nvmem_cell_post_process_t read_post_process; 578a134fd9SMichael Walle void *priv; 580749aa25SSrinivas Kandagatla struct device_node *np; 59eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem; 60eace75cfSSrinivas Kandagatla struct list_head node; 61eace75cfSSrinivas Kandagatla }; 62eace75cfSSrinivas Kandagatla 637ae6478bSSrinivas Kandagatla struct nvmem_cell { 647ae6478bSSrinivas Kandagatla struct nvmem_cell_entry *entry; 657ae6478bSSrinivas Kandagatla const char *id; 665d8e6e6cSMichael Walle int index; 677ae6478bSSrinivas Kandagatla }; 687ae6478bSSrinivas Kandagatla 69eace75cfSSrinivas Kandagatla static DEFINE_MUTEX(nvmem_mutex); 70eace75cfSSrinivas Kandagatla static DEFINE_IDA(nvmem_ida); 71eace75cfSSrinivas Kandagatla 72b985f4cbSBartosz Golaszewski static DEFINE_MUTEX(nvmem_cell_mutex); 73b985f4cbSBartosz Golaszewski static LIST_HEAD(nvmem_cell_tables); 74b985f4cbSBartosz Golaszewski 75506157beSBartosz Golaszewski static DEFINE_MUTEX(nvmem_lookup_mutex); 76506157beSBartosz Golaszewski static LIST_HEAD(nvmem_lookup_list); 77506157beSBartosz Golaszewski 78bee1138bSBartosz Golaszewski static BLOCKING_NOTIFIER_HEAD(nvmem_notifier); 79bee1138bSBartosz Golaszewski 80266570f4SMichael Walle static DEFINE_SPINLOCK(nvmem_layout_lock); 81266570f4SMichael Walle static LIST_HEAD(nvmem_layouts); 82266570f4SMichael Walle 83fd3bb8f5SEvan Green static int __nvmem_reg_read(struct nvmem_device *nvmem, unsigned int offset, 84b96fc541SMichael Auchter void *val, size_t bytes) 85b96fc541SMichael Auchter { 86b96fc541SMichael Auchter if (nvmem->reg_read) 87b96fc541SMichael Auchter return nvmem->reg_read(nvmem->priv, offset, val, bytes); 88b96fc541SMichael Auchter 89b96fc541SMichael Auchter return -EINVAL; 90b96fc541SMichael Auchter } 91b96fc541SMichael Auchter 92fd3bb8f5SEvan Green static int __nvmem_reg_write(struct nvmem_device *nvmem, unsigned int offset, 93b96fc541SMichael Auchter void *val, size_t bytes) 94b96fc541SMichael Auchter { 95b96fc541SMichael Auchter int ret; 96b96fc541SMichael Auchter 97b96fc541SMichael Auchter if (nvmem->reg_write) { 98b96fc541SMichael Auchter gpiod_set_value_cansleep(nvmem->wp_gpio, 0); 99b96fc541SMichael Auchter ret = nvmem->reg_write(nvmem->priv, offset, val, bytes); 100b96fc541SMichael Auchter gpiod_set_value_cansleep(nvmem->wp_gpio, 1); 101b96fc541SMichael Auchter return ret; 102b96fc541SMichael Auchter } 103b96fc541SMichael Auchter 104b96fc541SMichael Auchter return -EINVAL; 105b96fc541SMichael Auchter } 106b96fc541SMichael Auchter 107fd3bb8f5SEvan Green static int nvmem_access_with_keepouts(struct nvmem_device *nvmem, 108fd3bb8f5SEvan Green unsigned int offset, void *val, 109fd3bb8f5SEvan Green size_t bytes, int write) 110fd3bb8f5SEvan Green { 111fd3bb8f5SEvan Green 112fd3bb8f5SEvan Green unsigned int end = offset + bytes; 113fd3bb8f5SEvan Green unsigned int kend, ksize; 114fd3bb8f5SEvan Green const struct nvmem_keepout *keepout = nvmem->keepout; 115fd3bb8f5SEvan Green const struct nvmem_keepout *keepoutend = keepout + nvmem->nkeepout; 116fd3bb8f5SEvan Green int rc; 117fd3bb8f5SEvan Green 118fd3bb8f5SEvan Green /* 119fd3bb8f5SEvan Green * Skip all keepouts before the range being accessed. 120fd3bb8f5SEvan Green * Keepouts are sorted. 121fd3bb8f5SEvan Green */ 122fd3bb8f5SEvan Green while ((keepout < keepoutend) && (keepout->end <= offset)) 123fd3bb8f5SEvan Green keepout++; 124fd3bb8f5SEvan Green 125fd3bb8f5SEvan Green while ((offset < end) && (keepout < keepoutend)) { 126fd3bb8f5SEvan Green /* Access the valid portion before the keepout. */ 127fd3bb8f5SEvan Green if (offset < keepout->start) { 128fd3bb8f5SEvan Green kend = min(end, keepout->start); 129fd3bb8f5SEvan Green ksize = kend - offset; 130fd3bb8f5SEvan Green if (write) 131fd3bb8f5SEvan Green rc = __nvmem_reg_write(nvmem, offset, val, ksize); 132fd3bb8f5SEvan Green else 133fd3bb8f5SEvan Green rc = __nvmem_reg_read(nvmem, offset, val, ksize); 134fd3bb8f5SEvan Green 135fd3bb8f5SEvan Green if (rc) 136fd3bb8f5SEvan Green return rc; 137fd3bb8f5SEvan Green 138fd3bb8f5SEvan Green offset += ksize; 139fd3bb8f5SEvan Green val += ksize; 140fd3bb8f5SEvan Green } 141fd3bb8f5SEvan Green 142fd3bb8f5SEvan Green /* 143fd3bb8f5SEvan Green * Now we're aligned to the start of this keepout zone. Go 144fd3bb8f5SEvan Green * through it. 145fd3bb8f5SEvan Green */ 146fd3bb8f5SEvan Green kend = min(end, keepout->end); 147fd3bb8f5SEvan Green ksize = kend - offset; 148fd3bb8f5SEvan Green if (!write) 149fd3bb8f5SEvan Green memset(val, keepout->value, ksize); 150fd3bb8f5SEvan Green 151fd3bb8f5SEvan Green val += ksize; 152fd3bb8f5SEvan Green offset += ksize; 153fd3bb8f5SEvan Green keepout++; 154fd3bb8f5SEvan Green } 155fd3bb8f5SEvan Green 156fd3bb8f5SEvan Green /* 157fd3bb8f5SEvan Green * If we ran out of keepouts but there's still stuff to do, send it 158fd3bb8f5SEvan Green * down directly 159fd3bb8f5SEvan Green */ 160fd3bb8f5SEvan Green if (offset < end) { 161fd3bb8f5SEvan Green ksize = end - offset; 162fd3bb8f5SEvan Green if (write) 163fd3bb8f5SEvan Green return __nvmem_reg_write(nvmem, offset, val, ksize); 164fd3bb8f5SEvan Green else 165fd3bb8f5SEvan Green return __nvmem_reg_read(nvmem, offset, val, ksize); 166fd3bb8f5SEvan Green } 167fd3bb8f5SEvan Green 168fd3bb8f5SEvan Green return 0; 169fd3bb8f5SEvan Green } 170fd3bb8f5SEvan Green 171fd3bb8f5SEvan Green static int nvmem_reg_read(struct nvmem_device *nvmem, unsigned int offset, 172fd3bb8f5SEvan Green void *val, size_t bytes) 173fd3bb8f5SEvan Green { 174fd3bb8f5SEvan Green if (!nvmem->nkeepout) 175fd3bb8f5SEvan Green return __nvmem_reg_read(nvmem, offset, val, bytes); 176fd3bb8f5SEvan Green 177fd3bb8f5SEvan Green return nvmem_access_with_keepouts(nvmem, offset, val, bytes, false); 178fd3bb8f5SEvan Green } 179fd3bb8f5SEvan Green 180fd3bb8f5SEvan Green static int nvmem_reg_write(struct nvmem_device *nvmem, unsigned int offset, 181fd3bb8f5SEvan Green void *val, size_t bytes) 182fd3bb8f5SEvan Green { 183fd3bb8f5SEvan Green if (!nvmem->nkeepout) 184fd3bb8f5SEvan Green return __nvmem_reg_write(nvmem, offset, val, bytes); 185fd3bb8f5SEvan Green 186fd3bb8f5SEvan Green return nvmem_access_with_keepouts(nvmem, offset, val, bytes, true); 187fd3bb8f5SEvan Green } 188fd3bb8f5SEvan Green 18984400305SSrinivas Kandagatla #ifdef CONFIG_NVMEM_SYSFS 19084400305SSrinivas Kandagatla static const char * const nvmem_type_str[] = { 19184400305SSrinivas Kandagatla [NVMEM_TYPE_UNKNOWN] = "Unknown", 19284400305SSrinivas Kandagatla [NVMEM_TYPE_EEPROM] = "EEPROM", 19384400305SSrinivas Kandagatla [NVMEM_TYPE_OTP] = "OTP", 19484400305SSrinivas Kandagatla [NVMEM_TYPE_BATTERY_BACKED] = "Battery backed", 195fd307a4aSJiri Prchal [NVMEM_TYPE_FRAM] = "FRAM", 19684400305SSrinivas Kandagatla }; 19784400305SSrinivas Kandagatla 19884400305SSrinivas Kandagatla #ifdef CONFIG_DEBUG_LOCK_ALLOC 19984400305SSrinivas Kandagatla static struct lock_class_key eeprom_lock_key; 20084400305SSrinivas Kandagatla #endif 20184400305SSrinivas Kandagatla 20284400305SSrinivas Kandagatla static ssize_t type_show(struct device *dev, 20384400305SSrinivas Kandagatla struct device_attribute *attr, char *buf) 20484400305SSrinivas Kandagatla { 20584400305SSrinivas Kandagatla struct nvmem_device *nvmem = to_nvmem_device(dev); 20684400305SSrinivas Kandagatla 20784400305SSrinivas Kandagatla return sprintf(buf, "%s\n", nvmem_type_str[nvmem->type]); 20884400305SSrinivas Kandagatla } 20984400305SSrinivas Kandagatla 21084400305SSrinivas Kandagatla static DEVICE_ATTR_RO(type); 21184400305SSrinivas Kandagatla 21284400305SSrinivas Kandagatla static struct attribute *nvmem_attrs[] = { 21384400305SSrinivas Kandagatla &dev_attr_type.attr, 21484400305SSrinivas Kandagatla NULL, 21584400305SSrinivas Kandagatla }; 21684400305SSrinivas Kandagatla 21784400305SSrinivas Kandagatla static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj, 21884400305SSrinivas Kandagatla struct bin_attribute *attr, char *buf, 21984400305SSrinivas Kandagatla loff_t pos, size_t count) 22084400305SSrinivas Kandagatla { 22184400305SSrinivas Kandagatla struct device *dev; 22284400305SSrinivas Kandagatla struct nvmem_device *nvmem; 22384400305SSrinivas Kandagatla int rc; 22484400305SSrinivas Kandagatla 22584400305SSrinivas Kandagatla if (attr->private) 22684400305SSrinivas Kandagatla dev = attr->private; 22784400305SSrinivas Kandagatla else 22828371cc6STian Tao dev = kobj_to_dev(kobj); 22984400305SSrinivas Kandagatla nvmem = to_nvmem_device(dev); 23084400305SSrinivas Kandagatla 23184400305SSrinivas Kandagatla /* Stop the user from reading */ 23284400305SSrinivas Kandagatla if (pos >= nvmem->size) 23384400305SSrinivas Kandagatla return 0; 23484400305SSrinivas Kandagatla 23583566715SDouglas Anderson if (!IS_ALIGNED(pos, nvmem->stride)) 23683566715SDouglas Anderson return -EINVAL; 23783566715SDouglas Anderson 23884400305SSrinivas Kandagatla if (count < nvmem->word_size) 23984400305SSrinivas Kandagatla return -EINVAL; 24084400305SSrinivas Kandagatla 24184400305SSrinivas Kandagatla if (pos + count > nvmem->size) 24284400305SSrinivas Kandagatla count = nvmem->size - pos; 24384400305SSrinivas Kandagatla 24484400305SSrinivas Kandagatla count = round_down(count, nvmem->word_size); 24584400305SSrinivas Kandagatla 24684400305SSrinivas Kandagatla if (!nvmem->reg_read) 24784400305SSrinivas Kandagatla return -EPERM; 24884400305SSrinivas Kandagatla 249b96fc541SMichael Auchter rc = nvmem_reg_read(nvmem, pos, buf, count); 25084400305SSrinivas Kandagatla 25184400305SSrinivas Kandagatla if (rc) 25284400305SSrinivas Kandagatla return rc; 25384400305SSrinivas Kandagatla 25484400305SSrinivas Kandagatla return count; 25584400305SSrinivas Kandagatla } 25684400305SSrinivas Kandagatla 25784400305SSrinivas Kandagatla static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj, 25884400305SSrinivas Kandagatla struct bin_attribute *attr, char *buf, 25984400305SSrinivas Kandagatla loff_t pos, size_t count) 26084400305SSrinivas Kandagatla { 26184400305SSrinivas Kandagatla struct device *dev; 26284400305SSrinivas Kandagatla struct nvmem_device *nvmem; 26384400305SSrinivas Kandagatla int rc; 26484400305SSrinivas Kandagatla 26584400305SSrinivas Kandagatla if (attr->private) 26684400305SSrinivas Kandagatla dev = attr->private; 26784400305SSrinivas Kandagatla else 26828371cc6STian Tao dev = kobj_to_dev(kobj); 26984400305SSrinivas Kandagatla nvmem = to_nvmem_device(dev); 27084400305SSrinivas Kandagatla 27184400305SSrinivas Kandagatla /* Stop the user from writing */ 27284400305SSrinivas Kandagatla if (pos >= nvmem->size) 27384400305SSrinivas Kandagatla return -EFBIG; 27484400305SSrinivas Kandagatla 27583566715SDouglas Anderson if (!IS_ALIGNED(pos, nvmem->stride)) 27683566715SDouglas Anderson return -EINVAL; 27783566715SDouglas Anderson 27884400305SSrinivas Kandagatla if (count < nvmem->word_size) 27984400305SSrinivas Kandagatla return -EINVAL; 28084400305SSrinivas Kandagatla 28184400305SSrinivas Kandagatla if (pos + count > nvmem->size) 28284400305SSrinivas Kandagatla count = nvmem->size - pos; 28384400305SSrinivas Kandagatla 28484400305SSrinivas Kandagatla count = round_down(count, nvmem->word_size); 28584400305SSrinivas Kandagatla 28684400305SSrinivas Kandagatla if (!nvmem->reg_write) 28784400305SSrinivas Kandagatla return -EPERM; 28884400305SSrinivas Kandagatla 289b96fc541SMichael Auchter rc = nvmem_reg_write(nvmem, pos, buf, count); 29084400305SSrinivas Kandagatla 29184400305SSrinivas Kandagatla if (rc) 29284400305SSrinivas Kandagatla return rc; 29384400305SSrinivas Kandagatla 29484400305SSrinivas Kandagatla return count; 29584400305SSrinivas Kandagatla } 29684400305SSrinivas Kandagatla 2972a4542e5SSrinivas Kandagatla static umode_t nvmem_bin_attr_get_umode(struct nvmem_device *nvmem) 29884400305SSrinivas Kandagatla { 29984400305SSrinivas Kandagatla umode_t mode = 0400; 30084400305SSrinivas Kandagatla 30184400305SSrinivas Kandagatla if (!nvmem->root_only) 30284400305SSrinivas Kandagatla mode |= 0044; 30384400305SSrinivas Kandagatla 30484400305SSrinivas Kandagatla if (!nvmem->read_only) 30584400305SSrinivas Kandagatla mode |= 0200; 30684400305SSrinivas Kandagatla 30784400305SSrinivas Kandagatla if (!nvmem->reg_write) 30884400305SSrinivas Kandagatla mode &= ~0200; 30984400305SSrinivas Kandagatla 31084400305SSrinivas Kandagatla if (!nvmem->reg_read) 31184400305SSrinivas Kandagatla mode &= ~0444; 31284400305SSrinivas Kandagatla 31384400305SSrinivas Kandagatla return mode; 31484400305SSrinivas Kandagatla } 31584400305SSrinivas Kandagatla 3162a4542e5SSrinivas Kandagatla static umode_t nvmem_bin_attr_is_visible(struct kobject *kobj, 3172a4542e5SSrinivas Kandagatla struct bin_attribute *attr, int i) 3182a4542e5SSrinivas Kandagatla { 31928371cc6STian Tao struct device *dev = kobj_to_dev(kobj); 3202a4542e5SSrinivas Kandagatla struct nvmem_device *nvmem = to_nvmem_device(dev); 3212a4542e5SSrinivas Kandagatla 32286192251SSrinivas Kandagatla attr->size = nvmem->size; 32386192251SSrinivas Kandagatla 3242a4542e5SSrinivas Kandagatla return nvmem_bin_attr_get_umode(nvmem); 3252a4542e5SSrinivas Kandagatla } 3262a4542e5SSrinivas Kandagatla 32784400305SSrinivas Kandagatla /* default read/write permissions */ 32884400305SSrinivas Kandagatla static struct bin_attribute bin_attr_rw_nvmem = { 32984400305SSrinivas Kandagatla .attr = { 33084400305SSrinivas Kandagatla .name = "nvmem", 33184400305SSrinivas Kandagatla .mode = 0644, 33284400305SSrinivas Kandagatla }, 33384400305SSrinivas Kandagatla .read = bin_attr_nvmem_read, 33484400305SSrinivas Kandagatla .write = bin_attr_nvmem_write, 33584400305SSrinivas Kandagatla }; 33684400305SSrinivas Kandagatla 33784400305SSrinivas Kandagatla static struct bin_attribute *nvmem_bin_attributes[] = { 33884400305SSrinivas Kandagatla &bin_attr_rw_nvmem, 33984400305SSrinivas Kandagatla NULL, 34084400305SSrinivas Kandagatla }; 34184400305SSrinivas Kandagatla 34284400305SSrinivas Kandagatla static const struct attribute_group nvmem_bin_group = { 34384400305SSrinivas Kandagatla .bin_attrs = nvmem_bin_attributes, 34484400305SSrinivas Kandagatla .attrs = nvmem_attrs, 34584400305SSrinivas Kandagatla .is_bin_visible = nvmem_bin_attr_is_visible, 34684400305SSrinivas Kandagatla }; 34784400305SSrinivas Kandagatla 34884400305SSrinivas Kandagatla static const struct attribute_group *nvmem_dev_groups[] = { 34984400305SSrinivas Kandagatla &nvmem_bin_group, 35084400305SSrinivas Kandagatla NULL, 35184400305SSrinivas Kandagatla }; 35284400305SSrinivas Kandagatla 3532a4542e5SSrinivas Kandagatla static struct bin_attribute bin_attr_nvmem_eeprom_compat = { 35484400305SSrinivas Kandagatla .attr = { 3552a4542e5SSrinivas Kandagatla .name = "eeprom", 35684400305SSrinivas Kandagatla }, 35784400305SSrinivas Kandagatla .read = bin_attr_nvmem_read, 35884400305SSrinivas Kandagatla .write = bin_attr_nvmem_write, 35984400305SSrinivas Kandagatla }; 36084400305SSrinivas Kandagatla 36184400305SSrinivas Kandagatla /* 36284400305SSrinivas Kandagatla * nvmem_setup_compat() - Create an additional binary entry in 36384400305SSrinivas Kandagatla * drivers sys directory, to be backwards compatible with the older 36484400305SSrinivas Kandagatla * drivers/misc/eeprom drivers. 36584400305SSrinivas Kandagatla */ 36684400305SSrinivas Kandagatla static int nvmem_sysfs_setup_compat(struct nvmem_device *nvmem, 36784400305SSrinivas Kandagatla const struct nvmem_config *config) 36884400305SSrinivas Kandagatla { 36984400305SSrinivas Kandagatla int rval; 37084400305SSrinivas Kandagatla 37184400305SSrinivas Kandagatla if (!config->compat) 37284400305SSrinivas Kandagatla return 0; 37384400305SSrinivas Kandagatla 37484400305SSrinivas Kandagatla if (!config->base_dev) 37584400305SSrinivas Kandagatla return -EINVAL; 37684400305SSrinivas Kandagatla 377fd307a4aSJiri Prchal if (config->type == NVMEM_TYPE_FRAM) 378fd307a4aSJiri Prchal bin_attr_nvmem_eeprom_compat.attr.name = "fram"; 379fd307a4aSJiri Prchal 3802a4542e5SSrinivas Kandagatla nvmem->eeprom = bin_attr_nvmem_eeprom_compat; 3812a4542e5SSrinivas Kandagatla nvmem->eeprom.attr.mode = nvmem_bin_attr_get_umode(nvmem); 38284400305SSrinivas Kandagatla nvmem->eeprom.size = nvmem->size; 38384400305SSrinivas Kandagatla #ifdef CONFIG_DEBUG_LOCK_ALLOC 38484400305SSrinivas Kandagatla nvmem->eeprom.attr.key = &eeprom_lock_key; 38584400305SSrinivas Kandagatla #endif 38684400305SSrinivas Kandagatla nvmem->eeprom.private = &nvmem->dev; 38784400305SSrinivas Kandagatla nvmem->base_dev = config->base_dev; 38884400305SSrinivas Kandagatla 38984400305SSrinivas Kandagatla rval = device_create_bin_file(nvmem->base_dev, &nvmem->eeprom); 39084400305SSrinivas Kandagatla if (rval) { 39184400305SSrinivas Kandagatla dev_err(&nvmem->dev, 39284400305SSrinivas Kandagatla "Failed to create eeprom binary file %d\n", rval); 39384400305SSrinivas Kandagatla return rval; 39484400305SSrinivas Kandagatla } 39584400305SSrinivas Kandagatla 39684400305SSrinivas Kandagatla nvmem->flags |= FLAG_COMPAT; 39784400305SSrinivas Kandagatla 39884400305SSrinivas Kandagatla return 0; 39984400305SSrinivas Kandagatla } 40084400305SSrinivas Kandagatla 40184400305SSrinivas Kandagatla static void nvmem_sysfs_remove_compat(struct nvmem_device *nvmem, 40284400305SSrinivas Kandagatla const struct nvmem_config *config) 40384400305SSrinivas Kandagatla { 40484400305SSrinivas Kandagatla if (config->compat) 40584400305SSrinivas Kandagatla device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); 40684400305SSrinivas Kandagatla } 40784400305SSrinivas Kandagatla 40884400305SSrinivas Kandagatla #else /* CONFIG_NVMEM_SYSFS */ 40984400305SSrinivas Kandagatla 41084400305SSrinivas Kandagatla static int nvmem_sysfs_setup_compat(struct nvmem_device *nvmem, 41184400305SSrinivas Kandagatla const struct nvmem_config *config) 41284400305SSrinivas Kandagatla { 41384400305SSrinivas Kandagatla return -ENOSYS; 41484400305SSrinivas Kandagatla } 41584400305SSrinivas Kandagatla static void nvmem_sysfs_remove_compat(struct nvmem_device *nvmem, 41684400305SSrinivas Kandagatla const struct nvmem_config *config) 41784400305SSrinivas Kandagatla { 41884400305SSrinivas Kandagatla } 41984400305SSrinivas Kandagatla 42084400305SSrinivas Kandagatla #endif /* CONFIG_NVMEM_SYSFS */ 421a8b44d5dSAndy Shevchenko 422eace75cfSSrinivas Kandagatla static void nvmem_release(struct device *dev) 423eace75cfSSrinivas Kandagatla { 424eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem = to_nvmem_device(dev); 425eace75cfSSrinivas Kandagatla 4261eb51d6aSBartosz Golaszewski ida_free(&nvmem_ida, nvmem->id); 427a9c3766cSKhouloud Touil gpiod_put(nvmem->wp_gpio); 428eace75cfSSrinivas Kandagatla kfree(nvmem); 429eace75cfSSrinivas Kandagatla } 430eace75cfSSrinivas Kandagatla 431eace75cfSSrinivas Kandagatla static const struct device_type nvmem_provider_type = { 432eace75cfSSrinivas Kandagatla .release = nvmem_release, 433eace75cfSSrinivas Kandagatla }; 434eace75cfSSrinivas Kandagatla 435eace75cfSSrinivas Kandagatla static struct bus_type nvmem_bus_type = { 436eace75cfSSrinivas Kandagatla .name = "nvmem", 437eace75cfSSrinivas Kandagatla }; 438eace75cfSSrinivas Kandagatla 4397ae6478bSSrinivas Kandagatla static void nvmem_cell_entry_drop(struct nvmem_cell_entry *cell) 440eace75cfSSrinivas Kandagatla { 441bee1138bSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_REMOVE, cell); 442c7235ee3SBartosz Golaszewski mutex_lock(&nvmem_mutex); 443eace75cfSSrinivas Kandagatla list_del(&cell->node); 444c7235ee3SBartosz Golaszewski mutex_unlock(&nvmem_mutex); 4450749aa25SSrinivas Kandagatla of_node_put(cell->np); 44616bb7abcSBitan Biswas kfree_const(cell->name); 447eace75cfSSrinivas Kandagatla kfree(cell); 448eace75cfSSrinivas Kandagatla } 449eace75cfSSrinivas Kandagatla 450eace75cfSSrinivas Kandagatla static void nvmem_device_remove_all_cells(const struct nvmem_device *nvmem) 451eace75cfSSrinivas Kandagatla { 4527ae6478bSSrinivas Kandagatla struct nvmem_cell_entry *cell, *p; 453eace75cfSSrinivas Kandagatla 454c7235ee3SBartosz Golaszewski list_for_each_entry_safe(cell, p, &nvmem->cells, node) 4557ae6478bSSrinivas Kandagatla nvmem_cell_entry_drop(cell); 456eace75cfSSrinivas Kandagatla } 457eace75cfSSrinivas Kandagatla 4587ae6478bSSrinivas Kandagatla static void nvmem_cell_entry_add(struct nvmem_cell_entry *cell) 459eace75cfSSrinivas Kandagatla { 460c7235ee3SBartosz Golaszewski mutex_lock(&nvmem_mutex); 461c7235ee3SBartosz Golaszewski list_add_tail(&cell->node, &cell->nvmem->cells); 462c7235ee3SBartosz Golaszewski mutex_unlock(&nvmem_mutex); 463bee1138bSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_ADD, cell); 464eace75cfSSrinivas Kandagatla } 465eace75cfSSrinivas Kandagatla 4667ae6478bSSrinivas Kandagatla static int nvmem_cell_info_to_nvmem_cell_entry_nodup(struct nvmem_device *nvmem, 467eace75cfSSrinivas Kandagatla const struct nvmem_cell_info *info, 4687ae6478bSSrinivas Kandagatla struct nvmem_cell_entry *cell) 469eace75cfSSrinivas Kandagatla { 470eace75cfSSrinivas Kandagatla cell->nvmem = nvmem; 471eace75cfSSrinivas Kandagatla cell->offset = info->offset; 47255d4980cSRafał Miłecki cell->raw_len = info->raw_len ?: info->bytes; 473eace75cfSSrinivas Kandagatla cell->bytes = info->bytes; 474fc9eec4dSVadym Kochan cell->name = info->name; 475345ec382SMichael Walle cell->read_post_process = info->read_post_process; 4768a134fd9SMichael Walle cell->priv = info->priv; 477eace75cfSSrinivas Kandagatla 478eace75cfSSrinivas Kandagatla cell->bit_offset = info->bit_offset; 479eace75cfSSrinivas Kandagatla cell->nbits = info->nbits; 480dbc2f620SRafał Miłecki cell->np = info->np; 481eace75cfSSrinivas Kandagatla 482eace75cfSSrinivas Kandagatla if (cell->nbits) 483eace75cfSSrinivas Kandagatla cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset, 484eace75cfSSrinivas Kandagatla BITS_PER_BYTE); 485eace75cfSSrinivas Kandagatla 486eace75cfSSrinivas Kandagatla if (!IS_ALIGNED(cell->offset, nvmem->stride)) { 487eace75cfSSrinivas Kandagatla dev_err(&nvmem->dev, 488eace75cfSSrinivas Kandagatla "cell %s unaligned to nvmem stride %d\n", 489fc9eec4dSVadym Kochan cell->name ?: "<unknown>", nvmem->stride); 490eace75cfSSrinivas Kandagatla return -EINVAL; 491eace75cfSSrinivas Kandagatla } 492eace75cfSSrinivas Kandagatla 493eace75cfSSrinivas Kandagatla return 0; 494eace75cfSSrinivas Kandagatla } 495eace75cfSSrinivas Kandagatla 4967ae6478bSSrinivas Kandagatla static int nvmem_cell_info_to_nvmem_cell_entry(struct nvmem_device *nvmem, 497fc9eec4dSVadym Kochan const struct nvmem_cell_info *info, 4987ae6478bSSrinivas Kandagatla struct nvmem_cell_entry *cell) 499fc9eec4dSVadym Kochan { 500fc9eec4dSVadym Kochan int err; 501fc9eec4dSVadym Kochan 5027ae6478bSSrinivas Kandagatla err = nvmem_cell_info_to_nvmem_cell_entry_nodup(nvmem, info, cell); 503fc9eec4dSVadym Kochan if (err) 504fc9eec4dSVadym Kochan return err; 505fc9eec4dSVadym Kochan 506fc9eec4dSVadym Kochan cell->name = kstrdup_const(info->name, GFP_KERNEL); 507fc9eec4dSVadym Kochan if (!cell->name) 508fc9eec4dSVadym Kochan return -ENOMEM; 509fc9eec4dSVadym Kochan 510fc9eec4dSVadym Kochan return 0; 511fc9eec4dSVadym Kochan } 512fc9eec4dSVadym Kochan 513b3db17e4SAndrew Lunn /** 5142ded6830SMichael Walle * nvmem_add_one_cell() - Add one cell information to an nvmem device 5152ded6830SMichael Walle * 5162ded6830SMichael Walle * @nvmem: nvmem device to add cells to. 5172ded6830SMichael Walle * @info: nvmem cell info to add to the device 5182ded6830SMichael Walle * 5192ded6830SMichael Walle * Return: 0 or negative error code on failure. 5202ded6830SMichael Walle */ 5212ded6830SMichael Walle int nvmem_add_one_cell(struct nvmem_device *nvmem, 5222ded6830SMichael Walle const struct nvmem_cell_info *info) 5232ded6830SMichael Walle { 5242ded6830SMichael Walle struct nvmem_cell_entry *cell; 5252ded6830SMichael Walle int rval; 5262ded6830SMichael Walle 5272ded6830SMichael Walle cell = kzalloc(sizeof(*cell), GFP_KERNEL); 5282ded6830SMichael Walle if (!cell) 5292ded6830SMichael Walle return -ENOMEM; 5302ded6830SMichael Walle 5312ded6830SMichael Walle rval = nvmem_cell_info_to_nvmem_cell_entry(nvmem, info, cell); 5322ded6830SMichael Walle if (rval) { 5332ded6830SMichael Walle kfree(cell); 5342ded6830SMichael Walle return rval; 5352ded6830SMichael Walle } 5362ded6830SMichael Walle 5372ded6830SMichael Walle nvmem_cell_entry_add(cell); 5382ded6830SMichael Walle 5392ded6830SMichael Walle return 0; 5402ded6830SMichael Walle } 5412ded6830SMichael Walle EXPORT_SYMBOL_GPL(nvmem_add_one_cell); 5422ded6830SMichael Walle 5432ded6830SMichael Walle /** 544b3db17e4SAndrew Lunn * nvmem_add_cells() - Add cell information to an nvmem device 545b3db17e4SAndrew Lunn * 546b3db17e4SAndrew Lunn * @nvmem: nvmem device to add cells to. 547b3db17e4SAndrew Lunn * @info: nvmem cell info to add to the device 548b3db17e4SAndrew Lunn * @ncells: number of cells in info 549b3db17e4SAndrew Lunn * 550b3db17e4SAndrew Lunn * Return: 0 or negative error code on failure. 551b3db17e4SAndrew Lunn */ 552ef92ab30SSrinivas Kandagatla static int nvmem_add_cells(struct nvmem_device *nvmem, 553b3db17e4SAndrew Lunn const struct nvmem_cell_info *info, 554b3db17e4SAndrew Lunn int ncells) 555eace75cfSSrinivas Kandagatla { 5562ded6830SMichael Walle int i, rval; 557eace75cfSSrinivas Kandagatla 558b3db17e4SAndrew Lunn for (i = 0; i < ncells; i++) { 5592ded6830SMichael Walle rval = nvmem_add_one_cell(nvmem, &info[i]); 5602ded6830SMichael Walle if (rval) 561eace75cfSSrinivas Kandagatla return rval; 562eace75cfSSrinivas Kandagatla } 563eace75cfSSrinivas Kandagatla 5642ded6830SMichael Walle return 0; 5652ded6830SMichael Walle } 5662ded6830SMichael Walle 567bee1138bSBartosz Golaszewski /** 568bee1138bSBartosz Golaszewski * nvmem_register_notifier() - Register a notifier block for nvmem events. 569bee1138bSBartosz Golaszewski * 570bee1138bSBartosz Golaszewski * @nb: notifier block to be called on nvmem events. 571bee1138bSBartosz Golaszewski * 572bee1138bSBartosz Golaszewski * Return: 0 on success, negative error number on failure. 573bee1138bSBartosz Golaszewski */ 574bee1138bSBartosz Golaszewski int nvmem_register_notifier(struct notifier_block *nb) 575bee1138bSBartosz Golaszewski { 576bee1138bSBartosz Golaszewski return blocking_notifier_chain_register(&nvmem_notifier, nb); 577bee1138bSBartosz Golaszewski } 578bee1138bSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_register_notifier); 579bee1138bSBartosz Golaszewski 580bee1138bSBartosz Golaszewski /** 581bee1138bSBartosz Golaszewski * nvmem_unregister_notifier() - Unregister a notifier block for nvmem events. 582bee1138bSBartosz Golaszewski * 583bee1138bSBartosz Golaszewski * @nb: notifier block to be unregistered. 584bee1138bSBartosz Golaszewski * 585bee1138bSBartosz Golaszewski * Return: 0 on success, negative error number on failure. 586bee1138bSBartosz Golaszewski */ 587bee1138bSBartosz Golaszewski int nvmem_unregister_notifier(struct notifier_block *nb) 588bee1138bSBartosz Golaszewski { 589bee1138bSBartosz Golaszewski return blocking_notifier_chain_unregister(&nvmem_notifier, nb); 590bee1138bSBartosz Golaszewski } 591bee1138bSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_unregister_notifier); 592bee1138bSBartosz Golaszewski 593b985f4cbSBartosz Golaszewski static int nvmem_add_cells_from_table(struct nvmem_device *nvmem) 594b985f4cbSBartosz Golaszewski { 595b985f4cbSBartosz Golaszewski const struct nvmem_cell_info *info; 596b985f4cbSBartosz Golaszewski struct nvmem_cell_table *table; 5977ae6478bSSrinivas Kandagatla struct nvmem_cell_entry *cell; 598b985f4cbSBartosz Golaszewski int rval = 0, i; 599b985f4cbSBartosz Golaszewski 600b985f4cbSBartosz Golaszewski mutex_lock(&nvmem_cell_mutex); 601b985f4cbSBartosz Golaszewski list_for_each_entry(table, &nvmem_cell_tables, node) { 602b985f4cbSBartosz Golaszewski if (strcmp(nvmem_dev_name(nvmem), table->nvmem_name) == 0) { 603b985f4cbSBartosz Golaszewski for (i = 0; i < table->ncells; i++) { 604b985f4cbSBartosz Golaszewski info = &table->cells[i]; 605b985f4cbSBartosz Golaszewski 606b985f4cbSBartosz Golaszewski cell = kzalloc(sizeof(*cell), GFP_KERNEL); 607b985f4cbSBartosz Golaszewski if (!cell) { 608b985f4cbSBartosz Golaszewski rval = -ENOMEM; 609b985f4cbSBartosz Golaszewski goto out; 610b985f4cbSBartosz Golaszewski } 611b985f4cbSBartosz Golaszewski 6127ae6478bSSrinivas Kandagatla rval = nvmem_cell_info_to_nvmem_cell_entry(nvmem, info, cell); 613b985f4cbSBartosz Golaszewski if (rval) { 614b985f4cbSBartosz Golaszewski kfree(cell); 615b985f4cbSBartosz Golaszewski goto out; 616b985f4cbSBartosz Golaszewski } 617b985f4cbSBartosz Golaszewski 6187ae6478bSSrinivas Kandagatla nvmem_cell_entry_add(cell); 619b985f4cbSBartosz Golaszewski } 620b985f4cbSBartosz Golaszewski } 621b985f4cbSBartosz Golaszewski } 622b985f4cbSBartosz Golaszewski 623b985f4cbSBartosz Golaszewski out: 624b985f4cbSBartosz Golaszewski mutex_unlock(&nvmem_cell_mutex); 625b985f4cbSBartosz Golaszewski return rval; 626b985f4cbSBartosz Golaszewski } 627b985f4cbSBartosz Golaszewski 6287ae6478bSSrinivas Kandagatla static struct nvmem_cell_entry * 6297ae6478bSSrinivas Kandagatla nvmem_find_cell_entry_by_name(struct nvmem_device *nvmem, const char *cell_id) 630506157beSBartosz Golaszewski { 6317ae6478bSSrinivas Kandagatla struct nvmem_cell_entry *iter, *cell = NULL; 632506157beSBartosz Golaszewski 633506157beSBartosz Golaszewski mutex_lock(&nvmem_mutex); 6341c832674SAlban Bedel list_for_each_entry(iter, &nvmem->cells, node) { 6351c832674SAlban Bedel if (strcmp(cell_id, iter->name) == 0) { 6361c832674SAlban Bedel cell = iter; 637506157beSBartosz Golaszewski break; 638506157beSBartosz Golaszewski } 6391c832674SAlban Bedel } 640506157beSBartosz Golaszewski mutex_unlock(&nvmem_mutex); 641506157beSBartosz Golaszewski 642506157beSBartosz Golaszewski return cell; 643506157beSBartosz Golaszewski } 644506157beSBartosz Golaszewski 645fd3bb8f5SEvan Green static int nvmem_validate_keepouts(struct nvmem_device *nvmem) 646fd3bb8f5SEvan Green { 647fd3bb8f5SEvan Green unsigned int cur = 0; 648fd3bb8f5SEvan Green const struct nvmem_keepout *keepout = nvmem->keepout; 649fd3bb8f5SEvan Green const struct nvmem_keepout *keepoutend = keepout + nvmem->nkeepout; 650fd3bb8f5SEvan Green 651fd3bb8f5SEvan Green while (keepout < keepoutend) { 652fd3bb8f5SEvan Green /* Ensure keepouts are sorted and don't overlap. */ 653fd3bb8f5SEvan Green if (keepout->start < cur) { 654fd3bb8f5SEvan Green dev_err(&nvmem->dev, 655fd3bb8f5SEvan Green "Keepout regions aren't sorted or overlap.\n"); 656fd3bb8f5SEvan Green 657fd3bb8f5SEvan Green return -ERANGE; 658fd3bb8f5SEvan Green } 659fd3bb8f5SEvan Green 660fd3bb8f5SEvan Green if (keepout->end < keepout->start) { 661fd3bb8f5SEvan Green dev_err(&nvmem->dev, 662fd3bb8f5SEvan Green "Invalid keepout region.\n"); 663fd3bb8f5SEvan Green 664fd3bb8f5SEvan Green return -EINVAL; 665fd3bb8f5SEvan Green } 666fd3bb8f5SEvan Green 667fd3bb8f5SEvan Green /* 668fd3bb8f5SEvan Green * Validate keepouts (and holes between) don't violate 669fd3bb8f5SEvan Green * word_size constraints. 670fd3bb8f5SEvan Green */ 671fd3bb8f5SEvan Green if ((keepout->end - keepout->start < nvmem->word_size) || 672fd3bb8f5SEvan Green ((keepout->start != cur) && 673fd3bb8f5SEvan Green (keepout->start - cur < nvmem->word_size))) { 674fd3bb8f5SEvan Green 675fd3bb8f5SEvan Green dev_err(&nvmem->dev, 676fd3bb8f5SEvan Green "Keepout regions violate word_size constraints.\n"); 677fd3bb8f5SEvan Green 678fd3bb8f5SEvan Green return -ERANGE; 679fd3bb8f5SEvan Green } 680fd3bb8f5SEvan Green 681fd3bb8f5SEvan Green /* Validate keepouts don't violate stride (alignment). */ 682fd3bb8f5SEvan Green if (!IS_ALIGNED(keepout->start, nvmem->stride) || 683fd3bb8f5SEvan Green !IS_ALIGNED(keepout->end, nvmem->stride)) { 684fd3bb8f5SEvan Green 685fd3bb8f5SEvan Green dev_err(&nvmem->dev, 686fd3bb8f5SEvan Green "Keepout regions violate stride.\n"); 687fd3bb8f5SEvan Green 688fd3bb8f5SEvan Green return -EINVAL; 689fd3bb8f5SEvan Green } 690fd3bb8f5SEvan Green 691fd3bb8f5SEvan Green cur = keepout->end; 692fd3bb8f5SEvan Green keepout++; 693fd3bb8f5SEvan Green } 694fd3bb8f5SEvan Green 695fd3bb8f5SEvan Green return 0; 696fd3bb8f5SEvan Green } 697fd3bb8f5SEvan Green 69827f699e5SRafał Miłecki static int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_node *np) 699e888d445SBartosz Golaszewski { 700de12c969SMichael Walle struct nvmem_layout *layout = nvmem->layout; 701e888d445SBartosz Golaszewski struct device *dev = &nvmem->dev; 70250014d65SMichael Walle struct device_node *child; 703e888d445SBartosz Golaszewski const __be32 *addr; 70450014d65SMichael Walle int len, ret; 705e888d445SBartosz Golaszewski 70627f699e5SRafał Miłecki for_each_child_of_node(np, child) { 70750014d65SMichael Walle struct nvmem_cell_info info = {0}; 708e888d445SBartosz Golaszewski 709e888d445SBartosz Golaszewski addr = of_get_property(child, "reg", &len); 7100445efacSAhmad Fatoum if (!addr) 7110445efacSAhmad Fatoum continue; 7120445efacSAhmad Fatoum if (len < 2 * sizeof(u32)) { 713e888d445SBartosz Golaszewski dev_err(dev, "nvmem: invalid reg on %pOF\n", child); 71463879e29SChristophe JAILLET of_node_put(child); 715e888d445SBartosz Golaszewski return -EINVAL; 716e888d445SBartosz Golaszewski } 717e888d445SBartosz Golaszewski 71850014d65SMichael Walle info.offset = be32_to_cpup(addr++); 71950014d65SMichael Walle info.bytes = be32_to_cpup(addr); 72050014d65SMichael Walle info.name = kasprintf(GFP_KERNEL, "%pOFn", child); 721e888d445SBartosz Golaszewski 722e888d445SBartosz Golaszewski addr = of_get_property(child, "bits", &len); 723e888d445SBartosz Golaszewski if (addr && len == (2 * sizeof(u32))) { 72450014d65SMichael Walle info.bit_offset = be32_to_cpup(addr++); 72550014d65SMichael Walle info.nbits = be32_to_cpup(addr); 726e888d445SBartosz Golaszewski } 727e888d445SBartosz Golaszewski 72850014d65SMichael Walle info.np = of_node_get(child); 729e888d445SBartosz Golaszewski 730de12c969SMichael Walle if (layout && layout->fixup_cell_info) 731de12c969SMichael Walle layout->fixup_cell_info(nvmem, layout, &info); 732de12c969SMichael Walle 73350014d65SMichael Walle ret = nvmem_add_one_cell(nvmem, &info); 73450014d65SMichael Walle kfree(info.name); 73550014d65SMichael Walle if (ret) { 73663879e29SChristophe JAILLET of_node_put(child); 73750014d65SMichael Walle return ret; 738e888d445SBartosz Golaszewski } 739e888d445SBartosz Golaszewski } 740e888d445SBartosz Golaszewski 741e888d445SBartosz Golaszewski return 0; 742e888d445SBartosz Golaszewski } 743e888d445SBartosz Golaszewski 74427f699e5SRafał Miłecki static int nvmem_add_cells_from_legacy_of(struct nvmem_device *nvmem) 74527f699e5SRafał Miłecki { 74627f699e5SRafał Miłecki return nvmem_add_cells_from_dt(nvmem, nvmem->dev.of_node); 74727f699e5SRafał Miłecki } 74827f699e5SRafał Miłecki 74927f699e5SRafał Miłecki static int nvmem_add_cells_from_fixed_layout(struct nvmem_device *nvmem) 75027f699e5SRafał Miłecki { 75127f699e5SRafał Miłecki struct device_node *layout_np; 75227f699e5SRafał Miłecki int err = 0; 75327f699e5SRafał Miłecki 75427f699e5SRafał Miłecki layout_np = of_nvmem_layout_get_container(nvmem); 75527f699e5SRafał Miłecki if (!layout_np) 75627f699e5SRafał Miłecki return 0; 75727f699e5SRafał Miłecki 75827f699e5SRafał Miłecki if (of_device_is_compatible(layout_np, "fixed-layout")) 75927f699e5SRafał Miłecki err = nvmem_add_cells_from_dt(nvmem, layout_np); 76027f699e5SRafał Miłecki 76127f699e5SRafał Miłecki of_node_put(layout_np); 76227f699e5SRafał Miłecki 76327f699e5SRafał Miłecki return err; 76427f699e5SRafał Miłecki } 76527f699e5SRafał Miłecki 766266570f4SMichael Walle int __nvmem_layout_register(struct nvmem_layout *layout, struct module *owner) 767266570f4SMichael Walle { 768266570f4SMichael Walle layout->owner = owner; 769266570f4SMichael Walle 770266570f4SMichael Walle spin_lock(&nvmem_layout_lock); 771266570f4SMichael Walle list_add(&layout->node, &nvmem_layouts); 772266570f4SMichael Walle spin_unlock(&nvmem_layout_lock); 773266570f4SMichael Walle 774eb176cb4SMiquel Raynal blocking_notifier_call_chain(&nvmem_notifier, NVMEM_LAYOUT_ADD, layout); 775eb176cb4SMiquel Raynal 776266570f4SMichael Walle return 0; 777266570f4SMichael Walle } 778266570f4SMichael Walle EXPORT_SYMBOL_GPL(__nvmem_layout_register); 779266570f4SMichael Walle 780266570f4SMichael Walle void nvmem_layout_unregister(struct nvmem_layout *layout) 781266570f4SMichael Walle { 782eb176cb4SMiquel Raynal blocking_notifier_call_chain(&nvmem_notifier, NVMEM_LAYOUT_REMOVE, layout); 783eb176cb4SMiquel Raynal 784266570f4SMichael Walle spin_lock(&nvmem_layout_lock); 785266570f4SMichael Walle list_del(&layout->node); 786266570f4SMichael Walle spin_unlock(&nvmem_layout_lock); 787266570f4SMichael Walle } 788266570f4SMichael Walle EXPORT_SYMBOL_GPL(nvmem_layout_unregister); 789266570f4SMichael Walle 790266570f4SMichael Walle static struct nvmem_layout *nvmem_layout_get(struct nvmem_device *nvmem) 791266570f4SMichael Walle { 792b9740091SMiquel Raynal struct device_node *layout_np; 7936468a6f4SMiquel Raynal struct nvmem_layout *l, *layout = ERR_PTR(-EPROBE_DEFER); 794266570f4SMichael Walle 795b9740091SMiquel Raynal layout_np = of_nvmem_layout_get_container(nvmem); 796266570f4SMichael Walle if (!layout_np) 797266570f4SMichael Walle return NULL; 798266570f4SMichael Walle 799*b7c1e537SMiquel Raynal /* Fixed layouts don't have a matching driver */ 800*b7c1e537SMiquel Raynal if (of_device_is_compatible(layout_np, "fixed-layout")) { 801*b7c1e537SMiquel Raynal of_node_put(layout_np); 802*b7c1e537SMiquel Raynal return NULL; 803*b7c1e537SMiquel Raynal } 804*b7c1e537SMiquel Raynal 805b1c37becSMiquel Raynal /* 806b1c37becSMiquel Raynal * In case the nvmem device was built-in while the layout was built as a 807b1c37becSMiquel Raynal * module, we shall manually request the layout driver loading otherwise 808b1c37becSMiquel Raynal * we'll never have any match. 809b1c37becSMiquel Raynal */ 810b1c37becSMiquel Raynal of_request_module(layout_np); 811b1c37becSMiquel Raynal 812266570f4SMichael Walle spin_lock(&nvmem_layout_lock); 813266570f4SMichael Walle 814266570f4SMichael Walle list_for_each_entry(l, &nvmem_layouts, node) { 815266570f4SMichael Walle if (of_match_node(l->of_match_table, layout_np)) { 816266570f4SMichael Walle if (try_module_get(l->owner)) 817266570f4SMichael Walle layout = l; 818266570f4SMichael Walle 819266570f4SMichael Walle break; 820266570f4SMichael Walle } 821266570f4SMichael Walle } 822266570f4SMichael Walle 823266570f4SMichael Walle spin_unlock(&nvmem_layout_lock); 824266570f4SMichael Walle of_node_put(layout_np); 825266570f4SMichael Walle 826266570f4SMichael Walle return layout; 827266570f4SMichael Walle } 828266570f4SMichael Walle 829266570f4SMichael Walle static void nvmem_layout_put(struct nvmem_layout *layout) 830266570f4SMichael Walle { 831266570f4SMichael Walle if (layout) 832266570f4SMichael Walle module_put(layout->owner); 833266570f4SMichael Walle } 834266570f4SMichael Walle 835266570f4SMichael Walle static int nvmem_add_cells_from_layout(struct nvmem_device *nvmem) 836266570f4SMichael Walle { 837266570f4SMichael Walle struct nvmem_layout *layout = nvmem->layout; 838266570f4SMichael Walle int ret; 839266570f4SMichael Walle 840266570f4SMichael Walle if (layout && layout->add_cells) { 841266570f4SMichael Walle ret = layout->add_cells(&nvmem->dev, nvmem, layout); 842266570f4SMichael Walle if (ret) 843266570f4SMichael Walle return ret; 844266570f4SMichael Walle } 845266570f4SMichael Walle 846266570f4SMichael Walle return 0; 847266570f4SMichael Walle } 848266570f4SMichael Walle 849266570f4SMichael Walle #if IS_ENABLED(CONFIG_OF) 850266570f4SMichael Walle /** 851266570f4SMichael Walle * of_nvmem_layout_get_container() - Get OF node to layout container. 852266570f4SMichael Walle * 853266570f4SMichael Walle * @nvmem: nvmem device. 854266570f4SMichael Walle * 855266570f4SMichael Walle * Return: a node pointer with refcount incremented or NULL if no 856266570f4SMichael Walle * container exists. Use of_node_put() on it when done. 857266570f4SMichael Walle */ 858266570f4SMichael Walle struct device_node *of_nvmem_layout_get_container(struct nvmem_device *nvmem) 859266570f4SMichael Walle { 860266570f4SMichael Walle return of_get_child_by_name(nvmem->dev.of_node, "nvmem-layout"); 861266570f4SMichael Walle } 862266570f4SMichael Walle EXPORT_SYMBOL_GPL(of_nvmem_layout_get_container); 863266570f4SMichael Walle #endif 864266570f4SMichael Walle 865266570f4SMichael Walle const void *nvmem_layout_get_match_data(struct nvmem_device *nvmem, 866266570f4SMichael Walle struct nvmem_layout *layout) 867266570f4SMichael Walle { 868266570f4SMichael Walle struct device_node __maybe_unused *layout_np; 869266570f4SMichael Walle const struct of_device_id *match; 870266570f4SMichael Walle 871266570f4SMichael Walle layout_np = of_nvmem_layout_get_container(nvmem); 872266570f4SMichael Walle match = of_match_node(layout->of_match_table, layout_np); 873266570f4SMichael Walle 874266570f4SMichael Walle return match ? match->data : NULL; 875266570f4SMichael Walle } 876266570f4SMichael Walle EXPORT_SYMBOL_GPL(nvmem_layout_get_match_data); 877266570f4SMichael Walle 878eace75cfSSrinivas Kandagatla /** 879eace75cfSSrinivas Kandagatla * nvmem_register() - Register a nvmem device for given nvmem_config. 8803a758071SAndreas Färber * Also creates a binary entry in /sys/bus/nvmem/devices/dev-name/nvmem 881eace75cfSSrinivas Kandagatla * 882eace75cfSSrinivas Kandagatla * @config: nvmem device configuration with which nvmem device is created. 883eace75cfSSrinivas Kandagatla * 884eace75cfSSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device 885eace75cfSSrinivas Kandagatla * on success. 886eace75cfSSrinivas Kandagatla */ 887eace75cfSSrinivas Kandagatla 888eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem_register(const struct nvmem_config *config) 889eace75cfSSrinivas Kandagatla { 890eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem; 891eace75cfSSrinivas Kandagatla int rval; 892eace75cfSSrinivas Kandagatla 893eace75cfSSrinivas Kandagatla if (!config->dev) 894eace75cfSSrinivas Kandagatla return ERR_PTR(-EINVAL); 895eace75cfSSrinivas Kandagatla 896061a320bSSrinivas Kandagatla if (!config->reg_read && !config->reg_write) 897061a320bSSrinivas Kandagatla return ERR_PTR(-EINVAL); 898061a320bSSrinivas Kandagatla 899eace75cfSSrinivas Kandagatla nvmem = kzalloc(sizeof(*nvmem), GFP_KERNEL); 900eace75cfSSrinivas Kandagatla if (!nvmem) 901eace75cfSSrinivas Kandagatla return ERR_PTR(-ENOMEM); 902eace75cfSSrinivas Kandagatla 9031eb51d6aSBartosz Golaszewski rval = ida_alloc(&nvmem_ida, GFP_KERNEL); 904eace75cfSSrinivas Kandagatla if (rval < 0) { 905eace75cfSSrinivas Kandagatla kfree(nvmem); 906eace75cfSSrinivas Kandagatla return ERR_PTR(rval); 907eace75cfSSrinivas Kandagatla } 90831c6ff51SBartosz Golaszewski 9093bd747c7SRussell King (Oracle) nvmem->id = rval; 9103bd747c7SRussell King (Oracle) 911560181d3SRussell King (Oracle) nvmem->dev.type = &nvmem_provider_type; 912560181d3SRussell King (Oracle) nvmem->dev.bus = &nvmem_bus_type; 913560181d3SRussell King (Oracle) nvmem->dev.parent = config->dev; 914560181d3SRussell King (Oracle) 915560181d3SRussell King (Oracle) device_initialize(&nvmem->dev); 916560181d3SRussell King (Oracle) 917569653f0SRussell King (Oracle) if (!config->ignore_wp) 9182a127da4SKhouloud Touil nvmem->wp_gpio = gpiod_get_optional(config->dev, "wp", 9192a127da4SKhouloud Touil GPIOD_OUT_HIGH); 920f7d8d7dcSBartosz Golaszewski if (IS_ERR(nvmem->wp_gpio)) { 921f7d8d7dcSBartosz Golaszewski rval = PTR_ERR(nvmem->wp_gpio); 9220c4862b1SRussell King (Oracle) nvmem->wp_gpio = NULL; 923560181d3SRussell King (Oracle) goto err_put_device; 924f7d8d7dcSBartosz Golaszewski } 9252a127da4SKhouloud Touil 926c1de7f43SBartosz Golaszewski kref_init(&nvmem->refcnt); 927c7235ee3SBartosz Golaszewski INIT_LIST_HEAD(&nvmem->cells); 928c1de7f43SBartosz Golaszewski 929eace75cfSSrinivas Kandagatla nvmem->owner = config->owner; 93017eb18d6SMasahiro Yamada if (!nvmem->owner && config->dev->driver) 93117eb18d6SMasahiro Yamada nvmem->owner = config->dev->driver->owner; 93299897efdSHeiner Kallweit nvmem->stride = config->stride ?: 1; 93399897efdSHeiner Kallweit nvmem->word_size = config->word_size ?: 1; 934795ddd18SSrinivas Kandagatla nvmem->size = config->size; 935e6de179dSSrinivas Kandagatla nvmem->root_only = config->root_only; 936795ddd18SSrinivas Kandagatla nvmem->priv = config->priv; 93716688453SAlexandre Belloni nvmem->type = config->type; 938795ddd18SSrinivas Kandagatla nvmem->reg_read = config->reg_read; 939795ddd18SSrinivas Kandagatla nvmem->reg_write = config->reg_write; 940fd3bb8f5SEvan Green nvmem->keepout = config->keepout; 941fd3bb8f5SEvan Green nvmem->nkeepout = config->nkeepout; 9421333a677SMichael Walle if (config->of_node) 9431333a677SMichael Walle nvmem->dev.of_node = config->of_node; 944f4cf4e5dSRafał Miłecki else 945fc2f9970SHeiner Kallweit nvmem->dev.of_node = config->dev->of_node; 946fd0f4906SAndrey Smirnov 947731aa3faSSrinivas Kandagatla switch (config->id) { 948731aa3faSSrinivas Kandagatla case NVMEM_DEVID_NONE: 9495544e90cSGaosheng Cui rval = dev_set_name(&nvmem->dev, "%s", config->name); 950731aa3faSSrinivas Kandagatla break; 951731aa3faSSrinivas Kandagatla case NVMEM_DEVID_AUTO: 9525544e90cSGaosheng Cui rval = dev_set_name(&nvmem->dev, "%s%d", config->name, nvmem->id); 953731aa3faSSrinivas Kandagatla break; 954731aa3faSSrinivas Kandagatla default: 9555544e90cSGaosheng Cui rval = dev_set_name(&nvmem->dev, "%s%d", 9565253193dSAban Bedel config->name ? : "nvmem", 9575253193dSAban Bedel config->name ? config->id : nvmem->id); 958731aa3faSSrinivas Kandagatla break; 959fd0f4906SAndrey Smirnov } 960eace75cfSSrinivas Kandagatla 961560181d3SRussell King (Oracle) if (rval) 962560181d3SRussell King (Oracle) goto err_put_device; 9635544e90cSGaosheng Cui 9641716cfe8SAlban Bedel nvmem->read_only = device_property_present(config->dev, "read-only") || 9651716cfe8SAlban Bedel config->read_only || !nvmem->reg_write; 966eace75cfSSrinivas Kandagatla 96784400305SSrinivas Kandagatla #ifdef CONFIG_NVMEM_SYSFS 96884400305SSrinivas Kandagatla nvmem->dev.groups = nvmem_dev_groups; 96984400305SSrinivas Kandagatla #endif 970eace75cfSSrinivas Kandagatla 971bd124456SGaosheng Cui if (nvmem->nkeepout) { 972bd124456SGaosheng Cui rval = nvmem_validate_keepouts(nvmem); 973bd124456SGaosheng Cui if (rval) 974ab3428cfSRussell King (Oracle) goto err_put_device; 975bd124456SGaosheng Cui } 976bd124456SGaosheng Cui 977b6c217abSAndrew Lunn if (config->compat) { 978ae0c2d72SSrinivas Kandagatla rval = nvmem_sysfs_setup_compat(nvmem, config); 979b6c217abSAndrew Lunn if (rval) 980ab3428cfSRussell King (Oracle) goto err_put_device; 981eace75cfSSrinivas Kandagatla } 982eace75cfSSrinivas Kandagatla 983266570f4SMichael Walle /* 984266570f4SMichael Walle * If the driver supplied a layout by config->layout, the module 985266570f4SMichael Walle * pointer will be NULL and nvmem_layout_put() will be a noop. 986266570f4SMichael Walle */ 987266570f4SMichael Walle nvmem->layout = config->layout ?: nvmem_layout_get(nvmem); 9886468a6f4SMiquel Raynal if (IS_ERR(nvmem->layout)) { 9896468a6f4SMiquel Raynal rval = PTR_ERR(nvmem->layout); 9906468a6f4SMiquel Raynal nvmem->layout = NULL; 9916468a6f4SMiquel Raynal 9926468a6f4SMiquel Raynal if (rval == -EPROBE_DEFER) 9936468a6f4SMiquel Raynal goto err_teardown_compat; 9946468a6f4SMiquel Raynal } 995266570f4SMichael Walle 996fa72d847SBartosz Golaszewski if (config->cells) { 997fa72d847SBartosz Golaszewski rval = nvmem_add_cells(nvmem, config->cells, config->ncells); 998fa72d847SBartosz Golaszewski if (rval) 999db3546d5SMichael Walle goto err_remove_cells; 1000fa72d847SBartosz Golaszewski } 1001eace75cfSSrinivas Kandagatla 1002b985f4cbSBartosz Golaszewski rval = nvmem_add_cells_from_table(nvmem); 1003b985f4cbSBartosz Golaszewski if (rval) 1004b985f4cbSBartosz Golaszewski goto err_remove_cells; 1005b985f4cbSBartosz Golaszewski 10062cc3b37fSRafał Miłecki if (config->add_legacy_fixed_of_cells) { 100727f699e5SRafał Miłecki rval = nvmem_add_cells_from_legacy_of(nvmem); 1008e888d445SBartosz Golaszewski if (rval) 1009e888d445SBartosz Golaszewski goto err_remove_cells; 10102cc3b37fSRafał Miłecki } 1011e888d445SBartosz Golaszewski 101227f699e5SRafał Miłecki rval = nvmem_add_cells_from_fixed_layout(nvmem); 101327f699e5SRafał Miłecki if (rval) 101427f699e5SRafał Miłecki goto err_remove_cells; 101527f699e5SRafał Miłecki 1016266570f4SMichael Walle rval = nvmem_add_cells_from_layout(nvmem); 1017266570f4SMichael Walle if (rval) 1018266570f4SMichael Walle goto err_remove_cells; 1019266570f4SMichael Walle 1020f4d1d17eSMiquel Raynal dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name); 1021f4d1d17eSMiquel Raynal 1022f4d1d17eSMiquel Raynal rval = device_add(&nvmem->dev); 1023f4d1d17eSMiquel Raynal if (rval) 1024f4d1d17eSMiquel Raynal goto err_remove_cells; 1025f4d1d17eSMiquel Raynal 1026f4853e1cSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_ADD, nvmem); 1027bee1138bSBartosz Golaszewski 1028eace75cfSSrinivas Kandagatla return nvmem; 10293360acdfSJohan Hovold 1030b985f4cbSBartosz Golaszewski err_remove_cells: 1031b985f4cbSBartosz Golaszewski nvmem_device_remove_all_cells(nvmem); 1032266570f4SMichael Walle nvmem_layout_put(nvmem->layout); 10336468a6f4SMiquel Raynal err_teardown_compat: 1034fa72d847SBartosz Golaszewski if (config->compat) 1035ae0c2d72SSrinivas Kandagatla nvmem_sysfs_remove_compat(nvmem, config); 10363360acdfSJohan Hovold err_put_device: 10373360acdfSJohan Hovold put_device(&nvmem->dev); 10383360acdfSJohan Hovold 1039b6c217abSAndrew Lunn return ERR_PTR(rval); 1040eace75cfSSrinivas Kandagatla } 1041eace75cfSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_register); 1042eace75cfSSrinivas Kandagatla 1043c1de7f43SBartosz Golaszewski static void nvmem_device_release(struct kref *kref) 1044c1de7f43SBartosz Golaszewski { 1045c1de7f43SBartosz Golaszewski struct nvmem_device *nvmem; 1046c1de7f43SBartosz Golaszewski 1047c1de7f43SBartosz Golaszewski nvmem = container_of(kref, struct nvmem_device, refcnt); 1048c1de7f43SBartosz Golaszewski 1049bee1138bSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_REMOVE, nvmem); 1050bee1138bSBartosz Golaszewski 1051c1de7f43SBartosz Golaszewski if (nvmem->flags & FLAG_COMPAT) 1052c1de7f43SBartosz Golaszewski device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); 1053c1de7f43SBartosz Golaszewski 1054c1de7f43SBartosz Golaszewski nvmem_device_remove_all_cells(nvmem); 1055266570f4SMichael Walle nvmem_layout_put(nvmem->layout); 1056f60442ddSSrinivas Kandagatla device_unregister(&nvmem->dev); 1057c1de7f43SBartosz Golaszewski } 1058c1de7f43SBartosz Golaszewski 1059eace75cfSSrinivas Kandagatla /** 1060eace75cfSSrinivas Kandagatla * nvmem_unregister() - Unregister previously registered nvmem device 1061eace75cfSSrinivas Kandagatla * 1062eace75cfSSrinivas Kandagatla * @nvmem: Pointer to previously registered nvmem device. 1063eace75cfSSrinivas Kandagatla */ 1064bf58e882SBartosz Golaszewski void nvmem_unregister(struct nvmem_device *nvmem) 1065eace75cfSSrinivas Kandagatla { 10668c751e0dSAndy Shevchenko if (nvmem) 1067c1de7f43SBartosz Golaszewski kref_put(&nvmem->refcnt, nvmem_device_release); 1068eace75cfSSrinivas Kandagatla } 1069eace75cfSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_unregister); 1070eace75cfSSrinivas Kandagatla 10715825b2c6SAndy Shevchenko static void devm_nvmem_unregister(void *nvmem) 1072f1f50ecaSAndrey Smirnov { 10735825b2c6SAndy Shevchenko nvmem_unregister(nvmem); 1074f1f50ecaSAndrey Smirnov } 1075f1f50ecaSAndrey Smirnov 1076f1f50ecaSAndrey Smirnov /** 1077f1f50ecaSAndrey Smirnov * devm_nvmem_register() - Register a managed nvmem device for given 1078f1f50ecaSAndrey Smirnov * nvmem_config. 10793a758071SAndreas Färber * Also creates a binary entry in /sys/bus/nvmem/devices/dev-name/nvmem 1080f1f50ecaSAndrey Smirnov * 1081b378c779SSrinivas Kandagatla * @dev: Device that uses the nvmem device. 1082f1f50ecaSAndrey Smirnov * @config: nvmem device configuration with which nvmem device is created. 1083f1f50ecaSAndrey Smirnov * 1084f1f50ecaSAndrey Smirnov * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device 1085f1f50ecaSAndrey Smirnov * on success. 1086f1f50ecaSAndrey Smirnov */ 1087f1f50ecaSAndrey Smirnov struct nvmem_device *devm_nvmem_register(struct device *dev, 1088f1f50ecaSAndrey Smirnov const struct nvmem_config *config) 1089f1f50ecaSAndrey Smirnov { 10905825b2c6SAndy Shevchenko struct nvmem_device *nvmem; 10915825b2c6SAndy Shevchenko int ret; 1092f1f50ecaSAndrey Smirnov 1093f1f50ecaSAndrey Smirnov nvmem = nvmem_register(config); 10945825b2c6SAndy Shevchenko if (IS_ERR(nvmem)) 10955825b2c6SAndy Shevchenko return nvmem; 1096f1f50ecaSAndrey Smirnov 10975825b2c6SAndy Shevchenko ret = devm_add_action_or_reset(dev, devm_nvmem_unregister, nvmem); 10985825b2c6SAndy Shevchenko if (ret) 10995825b2c6SAndy Shevchenko return ERR_PTR(ret); 1100f1f50ecaSAndrey Smirnov 1101f1f50ecaSAndrey Smirnov return nvmem; 1102f1f50ecaSAndrey Smirnov } 1103f1f50ecaSAndrey Smirnov EXPORT_SYMBOL_GPL(devm_nvmem_register); 1104f1f50ecaSAndrey Smirnov 11058c2a2b8cSThomas Bogendoerfer static struct nvmem_device *__nvmem_device_get(void *data, 11068c2a2b8cSThomas Bogendoerfer int (*match)(struct device *dev, const void *data)) 110769aba794SSrinivas Kandagatla { 110869aba794SSrinivas Kandagatla struct nvmem_device *nvmem = NULL; 11098c2a2b8cSThomas Bogendoerfer struct device *dev; 111069aba794SSrinivas Kandagatla 1111c7235ee3SBartosz Golaszewski mutex_lock(&nvmem_mutex); 11128c2a2b8cSThomas Bogendoerfer dev = bus_find_device(&nvmem_bus_type, NULL, data, match); 11138c2a2b8cSThomas Bogendoerfer if (dev) 11148c2a2b8cSThomas Bogendoerfer nvmem = to_nvmem_device(dev); 111569aba794SSrinivas Kandagatla mutex_unlock(&nvmem_mutex); 1116c7235ee3SBartosz Golaszewski if (!nvmem) 1117c7235ee3SBartosz Golaszewski return ERR_PTR(-EPROBE_DEFER); 111869aba794SSrinivas Kandagatla 111969aba794SSrinivas Kandagatla if (!try_module_get(nvmem->owner)) { 112069aba794SSrinivas Kandagatla dev_err(&nvmem->dev, 112169aba794SSrinivas Kandagatla "could not increase module refcount for cell %s\n", 11225db652c9SBartosz Golaszewski nvmem_dev_name(nvmem)); 112369aba794SSrinivas Kandagatla 112473e9dc4dSAlban Bedel put_device(&nvmem->dev); 112569aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 112669aba794SSrinivas Kandagatla } 112769aba794SSrinivas Kandagatla 1128c1de7f43SBartosz Golaszewski kref_get(&nvmem->refcnt); 1129c1de7f43SBartosz Golaszewski 113069aba794SSrinivas Kandagatla return nvmem; 113169aba794SSrinivas Kandagatla } 113269aba794SSrinivas Kandagatla 113369aba794SSrinivas Kandagatla static void __nvmem_device_put(struct nvmem_device *nvmem) 113469aba794SSrinivas Kandagatla { 113573e9dc4dSAlban Bedel put_device(&nvmem->dev); 113669aba794SSrinivas Kandagatla module_put(nvmem->owner); 1137c1de7f43SBartosz Golaszewski kref_put(&nvmem->refcnt, nvmem_device_release); 113869aba794SSrinivas Kandagatla } 113969aba794SSrinivas Kandagatla 1140e701c67cSMasahiro Yamada #if IS_ENABLED(CONFIG_OF) 1141e2a5402eSSrinivas Kandagatla /** 1142e2a5402eSSrinivas Kandagatla * of_nvmem_device_get() - Get nvmem device from a given id 1143e2a5402eSSrinivas Kandagatla * 114429143268SVivek Gautam * @np: Device tree node that uses the nvmem device. 1145e2a5402eSSrinivas Kandagatla * @id: nvmem name from nvmem-names property. 1146e2a5402eSSrinivas Kandagatla * 1147e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device 1148e2a5402eSSrinivas Kandagatla * on success. 1149e2a5402eSSrinivas Kandagatla */ 1150e2a5402eSSrinivas Kandagatla struct nvmem_device *of_nvmem_device_get(struct device_node *np, const char *id) 1151e2a5402eSSrinivas Kandagatla { 1152e2a5402eSSrinivas Kandagatla 1153e2a5402eSSrinivas Kandagatla struct device_node *nvmem_np; 1154b1c194dcSVadym Kochan struct nvmem_device *nvmem; 1155d4e7fef1SAlban Bedel int index = 0; 1156e2a5402eSSrinivas Kandagatla 1157d4e7fef1SAlban Bedel if (id) 1158e2a5402eSSrinivas Kandagatla index = of_property_match_string(np, "nvmem-names", id); 1159e2a5402eSSrinivas Kandagatla 1160e2a5402eSSrinivas Kandagatla nvmem_np = of_parse_phandle(np, "nvmem", index); 1161e2a5402eSSrinivas Kandagatla if (!nvmem_np) 1162d4e7fef1SAlban Bedel return ERR_PTR(-ENOENT); 1163e2a5402eSSrinivas Kandagatla 1164b1c194dcSVadym Kochan nvmem = __nvmem_device_get(nvmem_np, device_match_of_node); 1165b1c194dcSVadym Kochan of_node_put(nvmem_np); 1166b1c194dcSVadym Kochan return nvmem; 1167e2a5402eSSrinivas Kandagatla } 1168e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_nvmem_device_get); 1169e2a5402eSSrinivas Kandagatla #endif 1170e2a5402eSSrinivas Kandagatla 1171e2a5402eSSrinivas Kandagatla /** 1172e2a5402eSSrinivas Kandagatla * nvmem_device_get() - Get nvmem device from a given id 1173e2a5402eSSrinivas Kandagatla * 117429143268SVivek Gautam * @dev: Device that uses the nvmem device. 117529143268SVivek Gautam * @dev_name: name of the requested nvmem device. 1176e2a5402eSSrinivas Kandagatla * 1177e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device 1178e2a5402eSSrinivas Kandagatla * on success. 1179e2a5402eSSrinivas Kandagatla */ 1180e2a5402eSSrinivas Kandagatla struct nvmem_device *nvmem_device_get(struct device *dev, const char *dev_name) 1181e2a5402eSSrinivas Kandagatla { 1182e2a5402eSSrinivas Kandagatla if (dev->of_node) { /* try dt first */ 1183e2a5402eSSrinivas Kandagatla struct nvmem_device *nvmem; 1184e2a5402eSSrinivas Kandagatla 1185e2a5402eSSrinivas Kandagatla nvmem = of_nvmem_device_get(dev->of_node, dev_name); 1186e2a5402eSSrinivas Kandagatla 1187e2a5402eSSrinivas Kandagatla if (!IS_ERR(nvmem) || PTR_ERR(nvmem) == -EPROBE_DEFER) 1188e2a5402eSSrinivas Kandagatla return nvmem; 1189e2a5402eSSrinivas Kandagatla 1190e2a5402eSSrinivas Kandagatla } 1191e2a5402eSSrinivas Kandagatla 11928c2a2b8cSThomas Bogendoerfer return __nvmem_device_get((void *)dev_name, device_match_name); 1193e2a5402eSSrinivas Kandagatla } 1194e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_get); 1195e2a5402eSSrinivas Kandagatla 11968c2a2b8cSThomas Bogendoerfer /** 11978c2a2b8cSThomas Bogendoerfer * nvmem_device_find() - Find nvmem device with matching function 11988c2a2b8cSThomas Bogendoerfer * 11998c2a2b8cSThomas Bogendoerfer * @data: Data to pass to match function 12008c2a2b8cSThomas Bogendoerfer * @match: Callback function to check device 12018c2a2b8cSThomas Bogendoerfer * 12028c2a2b8cSThomas Bogendoerfer * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device 12038c2a2b8cSThomas Bogendoerfer * on success. 12048c2a2b8cSThomas Bogendoerfer */ 12058c2a2b8cSThomas Bogendoerfer struct nvmem_device *nvmem_device_find(void *data, 12068c2a2b8cSThomas Bogendoerfer int (*match)(struct device *dev, const void *data)) 12078c2a2b8cSThomas Bogendoerfer { 12088c2a2b8cSThomas Bogendoerfer return __nvmem_device_get(data, match); 12098c2a2b8cSThomas Bogendoerfer } 12108c2a2b8cSThomas Bogendoerfer EXPORT_SYMBOL_GPL(nvmem_device_find); 12118c2a2b8cSThomas Bogendoerfer 1212e2a5402eSSrinivas Kandagatla static int devm_nvmem_device_match(struct device *dev, void *res, void *data) 1213e2a5402eSSrinivas Kandagatla { 1214e2a5402eSSrinivas Kandagatla struct nvmem_device **nvmem = res; 1215e2a5402eSSrinivas Kandagatla 1216e2a5402eSSrinivas Kandagatla if (WARN_ON(!nvmem || !*nvmem)) 1217e2a5402eSSrinivas Kandagatla return 0; 1218e2a5402eSSrinivas Kandagatla 1219e2a5402eSSrinivas Kandagatla return *nvmem == data; 1220e2a5402eSSrinivas Kandagatla } 1221e2a5402eSSrinivas Kandagatla 1222e2a5402eSSrinivas Kandagatla static void devm_nvmem_device_release(struct device *dev, void *res) 1223e2a5402eSSrinivas Kandagatla { 1224e2a5402eSSrinivas Kandagatla nvmem_device_put(*(struct nvmem_device **)res); 1225e2a5402eSSrinivas Kandagatla } 1226e2a5402eSSrinivas Kandagatla 1227e2a5402eSSrinivas Kandagatla /** 1228e2a5402eSSrinivas Kandagatla * devm_nvmem_device_put() - put alredy got nvmem device 1229e2a5402eSSrinivas Kandagatla * 123029143268SVivek Gautam * @dev: Device that uses the nvmem device. 1231e2a5402eSSrinivas Kandagatla * @nvmem: pointer to nvmem device allocated by devm_nvmem_cell_get(), 1232e2a5402eSSrinivas Kandagatla * that needs to be released. 1233e2a5402eSSrinivas Kandagatla */ 1234e2a5402eSSrinivas Kandagatla void devm_nvmem_device_put(struct device *dev, struct nvmem_device *nvmem) 1235e2a5402eSSrinivas Kandagatla { 1236e2a5402eSSrinivas Kandagatla int ret; 1237e2a5402eSSrinivas Kandagatla 1238e2a5402eSSrinivas Kandagatla ret = devres_release(dev, devm_nvmem_device_release, 1239e2a5402eSSrinivas Kandagatla devm_nvmem_device_match, nvmem); 1240e2a5402eSSrinivas Kandagatla 1241e2a5402eSSrinivas Kandagatla WARN_ON(ret); 1242e2a5402eSSrinivas Kandagatla } 1243e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_device_put); 1244e2a5402eSSrinivas Kandagatla 1245e2a5402eSSrinivas Kandagatla /** 1246e2a5402eSSrinivas Kandagatla * nvmem_device_put() - put alredy got nvmem device 1247e2a5402eSSrinivas Kandagatla * 1248e2a5402eSSrinivas Kandagatla * @nvmem: pointer to nvmem device that needs to be released. 1249e2a5402eSSrinivas Kandagatla */ 1250e2a5402eSSrinivas Kandagatla void nvmem_device_put(struct nvmem_device *nvmem) 1251e2a5402eSSrinivas Kandagatla { 1252e2a5402eSSrinivas Kandagatla __nvmem_device_put(nvmem); 1253e2a5402eSSrinivas Kandagatla } 1254e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_put); 1255e2a5402eSSrinivas Kandagatla 1256e2a5402eSSrinivas Kandagatla /** 1257e2a5402eSSrinivas Kandagatla * devm_nvmem_device_get() - Get nvmem cell of device form a given id 1258e2a5402eSSrinivas Kandagatla * 125929143268SVivek Gautam * @dev: Device that requests the nvmem device. 126029143268SVivek Gautam * @id: name id for the requested nvmem device. 1261e2a5402eSSrinivas Kandagatla * 1262e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_cell 1263e2a5402eSSrinivas Kandagatla * on success. The nvmem_cell will be freed by the automatically once the 1264e2a5402eSSrinivas Kandagatla * device is freed. 1265e2a5402eSSrinivas Kandagatla */ 1266e2a5402eSSrinivas Kandagatla struct nvmem_device *devm_nvmem_device_get(struct device *dev, const char *id) 1267e2a5402eSSrinivas Kandagatla { 1268e2a5402eSSrinivas Kandagatla struct nvmem_device **ptr, *nvmem; 1269e2a5402eSSrinivas Kandagatla 1270e2a5402eSSrinivas Kandagatla ptr = devres_alloc(devm_nvmem_device_release, sizeof(*ptr), GFP_KERNEL); 1271e2a5402eSSrinivas Kandagatla if (!ptr) 1272e2a5402eSSrinivas Kandagatla return ERR_PTR(-ENOMEM); 1273e2a5402eSSrinivas Kandagatla 1274e2a5402eSSrinivas Kandagatla nvmem = nvmem_device_get(dev, id); 1275e2a5402eSSrinivas Kandagatla if (!IS_ERR(nvmem)) { 1276e2a5402eSSrinivas Kandagatla *ptr = nvmem; 1277e2a5402eSSrinivas Kandagatla devres_add(dev, ptr); 1278e2a5402eSSrinivas Kandagatla } else { 1279e2a5402eSSrinivas Kandagatla devres_free(ptr); 1280e2a5402eSSrinivas Kandagatla } 1281e2a5402eSSrinivas Kandagatla 1282e2a5402eSSrinivas Kandagatla return nvmem; 1283e2a5402eSSrinivas Kandagatla } 1284e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_device_get); 1285e2a5402eSSrinivas Kandagatla 12865d8e6e6cSMichael Walle static struct nvmem_cell *nvmem_create_cell(struct nvmem_cell_entry *entry, 12875d8e6e6cSMichael Walle const char *id, int index) 12887ae6478bSSrinivas Kandagatla { 12897ae6478bSSrinivas Kandagatla struct nvmem_cell *cell; 12907ae6478bSSrinivas Kandagatla const char *name = NULL; 12917ae6478bSSrinivas Kandagatla 12927ae6478bSSrinivas Kandagatla cell = kzalloc(sizeof(*cell), GFP_KERNEL); 12937ae6478bSSrinivas Kandagatla if (!cell) 12947ae6478bSSrinivas Kandagatla return ERR_PTR(-ENOMEM); 12957ae6478bSSrinivas Kandagatla 12967ae6478bSSrinivas Kandagatla if (id) { 12977ae6478bSSrinivas Kandagatla name = kstrdup_const(id, GFP_KERNEL); 12987ae6478bSSrinivas Kandagatla if (!name) { 12997ae6478bSSrinivas Kandagatla kfree(cell); 13007ae6478bSSrinivas Kandagatla return ERR_PTR(-ENOMEM); 13017ae6478bSSrinivas Kandagatla } 13027ae6478bSSrinivas Kandagatla } 13037ae6478bSSrinivas Kandagatla 13047ae6478bSSrinivas Kandagatla cell->id = name; 13057ae6478bSSrinivas Kandagatla cell->entry = entry; 13065d8e6e6cSMichael Walle cell->index = index; 13077ae6478bSSrinivas Kandagatla 13087ae6478bSSrinivas Kandagatla return cell; 13097ae6478bSSrinivas Kandagatla } 13107ae6478bSSrinivas Kandagatla 1311506157beSBartosz Golaszewski static struct nvmem_cell * 1312506157beSBartosz Golaszewski nvmem_cell_get_from_lookup(struct device *dev, const char *con_id) 131369aba794SSrinivas Kandagatla { 13147ae6478bSSrinivas Kandagatla struct nvmem_cell_entry *cell_entry; 1315506157beSBartosz Golaszewski struct nvmem_cell *cell = ERR_PTR(-ENOENT); 1316506157beSBartosz Golaszewski struct nvmem_cell_lookup *lookup; 131769aba794SSrinivas Kandagatla struct nvmem_device *nvmem; 1318506157beSBartosz Golaszewski const char *dev_id; 131969aba794SSrinivas Kandagatla 1320506157beSBartosz Golaszewski if (!dev) 1321506157beSBartosz Golaszewski return ERR_PTR(-EINVAL); 132269aba794SSrinivas Kandagatla 1323506157beSBartosz Golaszewski dev_id = dev_name(dev); 1324506157beSBartosz Golaszewski 1325506157beSBartosz Golaszewski mutex_lock(&nvmem_lookup_mutex); 1326506157beSBartosz Golaszewski 1327506157beSBartosz Golaszewski list_for_each_entry(lookup, &nvmem_lookup_list, node) { 1328506157beSBartosz Golaszewski if ((strcmp(lookup->dev_id, dev_id) == 0) && 1329506157beSBartosz Golaszewski (strcmp(lookup->con_id, con_id) == 0)) { 1330506157beSBartosz Golaszewski /* This is the right entry. */ 13318c2a2b8cSThomas Bogendoerfer nvmem = __nvmem_device_get((void *)lookup->nvmem_name, 13328c2a2b8cSThomas Bogendoerfer device_match_name); 1333cccb3b19SBartosz Golaszewski if (IS_ERR(nvmem)) { 1334506157beSBartosz Golaszewski /* Provider may not be registered yet. */ 1335cccb3b19SBartosz Golaszewski cell = ERR_CAST(nvmem); 13369bfd8198SAlban Bedel break; 1337506157beSBartosz Golaszewski } 1338506157beSBartosz Golaszewski 13397ae6478bSSrinivas Kandagatla cell_entry = nvmem_find_cell_entry_by_name(nvmem, 1340506157beSBartosz Golaszewski lookup->cell_name); 13417ae6478bSSrinivas Kandagatla if (!cell_entry) { 1342506157beSBartosz Golaszewski __nvmem_device_put(nvmem); 1343cccb3b19SBartosz Golaszewski cell = ERR_PTR(-ENOENT); 13447ae6478bSSrinivas Kandagatla } else { 13455d8e6e6cSMichael Walle cell = nvmem_create_cell(cell_entry, con_id, 0); 13467ae6478bSSrinivas Kandagatla if (IS_ERR(cell)) 13477ae6478bSSrinivas Kandagatla __nvmem_device_put(nvmem); 1348506157beSBartosz Golaszewski } 13499bfd8198SAlban Bedel break; 1350506157beSBartosz Golaszewski } 1351506157beSBartosz Golaszewski } 1352506157beSBartosz Golaszewski 1353506157beSBartosz Golaszewski mutex_unlock(&nvmem_lookup_mutex); 135469aba794SSrinivas Kandagatla return cell; 135569aba794SSrinivas Kandagatla } 135669aba794SSrinivas Kandagatla 1357e701c67cSMasahiro Yamada #if IS_ENABLED(CONFIG_OF) 13587ae6478bSSrinivas Kandagatla static struct nvmem_cell_entry * 13597ae6478bSSrinivas Kandagatla nvmem_find_cell_entry_by_node(struct nvmem_device *nvmem, struct device_node *np) 13603c53e235SArnd Bergmann { 13617ae6478bSSrinivas Kandagatla struct nvmem_cell_entry *iter, *cell = NULL; 13623c53e235SArnd Bergmann 13633c53e235SArnd Bergmann mutex_lock(&nvmem_mutex); 13641c832674SAlban Bedel list_for_each_entry(iter, &nvmem->cells, node) { 13651c832674SAlban Bedel if (np == iter->np) { 13661c832674SAlban Bedel cell = iter; 13673c53e235SArnd Bergmann break; 13683c53e235SArnd Bergmann } 13691c832674SAlban Bedel } 13703c53e235SArnd Bergmann mutex_unlock(&nvmem_mutex); 13713c53e235SArnd Bergmann 13723c53e235SArnd Bergmann return cell; 13733c53e235SArnd Bergmann } 13743c53e235SArnd Bergmann 137569aba794SSrinivas Kandagatla /** 137669aba794SSrinivas Kandagatla * of_nvmem_cell_get() - Get a nvmem cell from given device node and cell id 137769aba794SSrinivas Kandagatla * 137829143268SVivek Gautam * @np: Device tree node that uses the nvmem cell. 1379165589f0SBartosz Golaszewski * @id: nvmem cell name from nvmem-cell-names property, or NULL 1380fd0c478cSVivek Gautam * for the cell at index 0 (the lone cell with no accompanying 1381fd0c478cSVivek Gautam * nvmem-cell-names property). 138269aba794SSrinivas Kandagatla * 138369aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 138469aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 138569aba794SSrinivas Kandagatla * nvmem_cell_put(). 138669aba794SSrinivas Kandagatla */ 1387165589f0SBartosz Golaszewski struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *id) 138869aba794SSrinivas Kandagatla { 138969aba794SSrinivas Kandagatla struct device_node *cell_np, *nvmem_np; 139069aba794SSrinivas Kandagatla struct nvmem_device *nvmem; 13917ae6478bSSrinivas Kandagatla struct nvmem_cell_entry *cell_entry; 1392e888d445SBartosz Golaszewski struct nvmem_cell *cell; 13935d8e6e6cSMichael Walle struct of_phandle_args cell_spec; 1394fd0c478cSVivek Gautam int index = 0; 13955d8e6e6cSMichael Walle int cell_index = 0; 13965d8e6e6cSMichael Walle int ret; 139769aba794SSrinivas Kandagatla 1398fd0c478cSVivek Gautam /* if cell name exists, find index to the name */ 1399165589f0SBartosz Golaszewski if (id) 1400165589f0SBartosz Golaszewski index = of_property_match_string(np, "nvmem-cell-names", id); 140169aba794SSrinivas Kandagatla 14025d8e6e6cSMichael Walle ret = of_parse_phandle_with_optional_args(np, "nvmem-cells", 14035d8e6e6cSMichael Walle "#nvmem-cell-cells", 14045d8e6e6cSMichael Walle index, &cell_spec); 14055d8e6e6cSMichael Walle if (ret) 140606be6208SMichael Walle return ERR_PTR(-ENOENT); 14075d8e6e6cSMichael Walle 14085d8e6e6cSMichael Walle if (cell_spec.args_count > 1) 14095d8e6e6cSMichael Walle return ERR_PTR(-EINVAL); 14105d8e6e6cSMichael Walle 14115d8e6e6cSMichael Walle cell_np = cell_spec.np; 14125d8e6e6cSMichael Walle if (cell_spec.args_count) 14135d8e6e6cSMichael Walle cell_index = cell_spec.args[0]; 141469aba794SSrinivas Kandagatla 1415edcf2fb6SMichael Walle nvmem_np = of_get_parent(cell_np); 1416edcf2fb6SMichael Walle if (!nvmem_np) { 1417edcf2fb6SMichael Walle of_node_put(cell_np); 141869aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 1419edcf2fb6SMichael Walle } 142069aba794SSrinivas Kandagatla 1421266570f4SMichael Walle /* nvmem layouts produce cells within the nvmem-layout container */ 1422266570f4SMichael Walle if (of_node_name_eq(nvmem_np, "nvmem-layout")) { 1423266570f4SMichael Walle nvmem_np = of_get_next_parent(nvmem_np); 1424266570f4SMichael Walle if (!nvmem_np) { 1425266570f4SMichael Walle of_node_put(cell_np); 1426266570f4SMichael Walle return ERR_PTR(-EINVAL); 1427266570f4SMichael Walle } 1428266570f4SMichael Walle } 1429266570f4SMichael Walle 14308c2a2b8cSThomas Bogendoerfer nvmem = __nvmem_device_get(nvmem_np, device_match_of_node); 1431aad8d097SMasahiro Yamada of_node_put(nvmem_np); 1432edcf2fb6SMichael Walle if (IS_ERR(nvmem)) { 1433edcf2fb6SMichael Walle of_node_put(cell_np); 143469aba794SSrinivas Kandagatla return ERR_CAST(nvmem); 1435edcf2fb6SMichael Walle } 143669aba794SSrinivas Kandagatla 14377ae6478bSSrinivas Kandagatla cell_entry = nvmem_find_cell_entry_by_node(nvmem, cell_np); 1438edcf2fb6SMichael Walle of_node_put(cell_np); 14397ae6478bSSrinivas Kandagatla if (!cell_entry) { 1440e888d445SBartosz Golaszewski __nvmem_device_put(nvmem); 1441e888d445SBartosz Golaszewski return ERR_PTR(-ENOENT); 144269aba794SSrinivas Kandagatla } 144369aba794SSrinivas Kandagatla 14445d8e6e6cSMichael Walle cell = nvmem_create_cell(cell_entry, id, cell_index); 14457ae6478bSSrinivas Kandagatla if (IS_ERR(cell)) 14467ae6478bSSrinivas Kandagatla __nvmem_device_put(nvmem); 14477ae6478bSSrinivas Kandagatla 144869aba794SSrinivas Kandagatla return cell; 144969aba794SSrinivas Kandagatla } 145069aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_nvmem_cell_get); 145169aba794SSrinivas Kandagatla #endif 145269aba794SSrinivas Kandagatla 145369aba794SSrinivas Kandagatla /** 145469aba794SSrinivas Kandagatla * nvmem_cell_get() - Get nvmem cell of device form a given cell name 145569aba794SSrinivas Kandagatla * 145629143268SVivek Gautam * @dev: Device that requests the nvmem cell. 1457165589f0SBartosz Golaszewski * @id: nvmem cell name to get (this corresponds with the name from the 1458165589f0SBartosz Golaszewski * nvmem-cell-names property for DT systems and with the con_id from 1459165589f0SBartosz Golaszewski * the lookup entry for non-DT systems). 146069aba794SSrinivas Kandagatla * 146169aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 146269aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 146369aba794SSrinivas Kandagatla * nvmem_cell_put(). 146469aba794SSrinivas Kandagatla */ 1465165589f0SBartosz Golaszewski struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *id) 146669aba794SSrinivas Kandagatla { 146769aba794SSrinivas Kandagatla struct nvmem_cell *cell; 146869aba794SSrinivas Kandagatla 146969aba794SSrinivas Kandagatla if (dev->of_node) { /* try dt first */ 1470165589f0SBartosz Golaszewski cell = of_nvmem_cell_get(dev->of_node, id); 147169aba794SSrinivas Kandagatla if (!IS_ERR(cell) || PTR_ERR(cell) == -EPROBE_DEFER) 147269aba794SSrinivas Kandagatla return cell; 147369aba794SSrinivas Kandagatla } 147469aba794SSrinivas Kandagatla 1475165589f0SBartosz Golaszewski /* NULL cell id only allowed for device tree; invalid otherwise */ 1476165589f0SBartosz Golaszewski if (!id) 147787ed1405SDouglas Anderson return ERR_PTR(-EINVAL); 147887ed1405SDouglas Anderson 1479165589f0SBartosz Golaszewski return nvmem_cell_get_from_lookup(dev, id); 148069aba794SSrinivas Kandagatla } 148169aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_get); 148269aba794SSrinivas Kandagatla 148369aba794SSrinivas Kandagatla static void devm_nvmem_cell_release(struct device *dev, void *res) 148469aba794SSrinivas Kandagatla { 148569aba794SSrinivas Kandagatla nvmem_cell_put(*(struct nvmem_cell **)res); 148669aba794SSrinivas Kandagatla } 148769aba794SSrinivas Kandagatla 148869aba794SSrinivas Kandagatla /** 148969aba794SSrinivas Kandagatla * devm_nvmem_cell_get() - Get nvmem cell of device form a given id 149069aba794SSrinivas Kandagatla * 149129143268SVivek Gautam * @dev: Device that requests the nvmem cell. 149229143268SVivek Gautam * @id: nvmem cell name id to get. 149369aba794SSrinivas Kandagatla * 149469aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 149569aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 149669aba794SSrinivas Kandagatla * automatically once the device is freed. 149769aba794SSrinivas Kandagatla */ 149869aba794SSrinivas Kandagatla struct nvmem_cell *devm_nvmem_cell_get(struct device *dev, const char *id) 149969aba794SSrinivas Kandagatla { 150069aba794SSrinivas Kandagatla struct nvmem_cell **ptr, *cell; 150169aba794SSrinivas Kandagatla 150269aba794SSrinivas Kandagatla ptr = devres_alloc(devm_nvmem_cell_release, sizeof(*ptr), GFP_KERNEL); 150369aba794SSrinivas Kandagatla if (!ptr) 150469aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 150569aba794SSrinivas Kandagatla 150669aba794SSrinivas Kandagatla cell = nvmem_cell_get(dev, id); 150769aba794SSrinivas Kandagatla if (!IS_ERR(cell)) { 150869aba794SSrinivas Kandagatla *ptr = cell; 150969aba794SSrinivas Kandagatla devres_add(dev, ptr); 151069aba794SSrinivas Kandagatla } else { 151169aba794SSrinivas Kandagatla devres_free(ptr); 151269aba794SSrinivas Kandagatla } 151369aba794SSrinivas Kandagatla 151469aba794SSrinivas Kandagatla return cell; 151569aba794SSrinivas Kandagatla } 151669aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_cell_get); 151769aba794SSrinivas Kandagatla 151869aba794SSrinivas Kandagatla static int devm_nvmem_cell_match(struct device *dev, void *res, void *data) 151969aba794SSrinivas Kandagatla { 152069aba794SSrinivas Kandagatla struct nvmem_cell **c = res; 152169aba794SSrinivas Kandagatla 152269aba794SSrinivas Kandagatla if (WARN_ON(!c || !*c)) 152369aba794SSrinivas Kandagatla return 0; 152469aba794SSrinivas Kandagatla 152569aba794SSrinivas Kandagatla return *c == data; 152669aba794SSrinivas Kandagatla } 152769aba794SSrinivas Kandagatla 152869aba794SSrinivas Kandagatla /** 152969aba794SSrinivas Kandagatla * devm_nvmem_cell_put() - Release previously allocated nvmem cell 153069aba794SSrinivas Kandagatla * from devm_nvmem_cell_get. 153169aba794SSrinivas Kandagatla * 153229143268SVivek Gautam * @dev: Device that requests the nvmem cell. 153329143268SVivek Gautam * @cell: Previously allocated nvmem cell by devm_nvmem_cell_get(). 153469aba794SSrinivas Kandagatla */ 153569aba794SSrinivas Kandagatla void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell) 153669aba794SSrinivas Kandagatla { 153769aba794SSrinivas Kandagatla int ret; 153869aba794SSrinivas Kandagatla 153969aba794SSrinivas Kandagatla ret = devres_release(dev, devm_nvmem_cell_release, 154069aba794SSrinivas Kandagatla devm_nvmem_cell_match, cell); 154169aba794SSrinivas Kandagatla 154269aba794SSrinivas Kandagatla WARN_ON(ret); 154369aba794SSrinivas Kandagatla } 154469aba794SSrinivas Kandagatla EXPORT_SYMBOL(devm_nvmem_cell_put); 154569aba794SSrinivas Kandagatla 154669aba794SSrinivas Kandagatla /** 154769aba794SSrinivas Kandagatla * nvmem_cell_put() - Release previously allocated nvmem cell. 154869aba794SSrinivas Kandagatla * 154929143268SVivek Gautam * @cell: Previously allocated nvmem cell by nvmem_cell_get(). 155069aba794SSrinivas Kandagatla */ 155169aba794SSrinivas Kandagatla void nvmem_cell_put(struct nvmem_cell *cell) 155269aba794SSrinivas Kandagatla { 15537ae6478bSSrinivas Kandagatla struct nvmem_device *nvmem = cell->entry->nvmem; 155469aba794SSrinivas Kandagatla 15557ae6478bSSrinivas Kandagatla if (cell->id) 15567ae6478bSSrinivas Kandagatla kfree_const(cell->id); 15577ae6478bSSrinivas Kandagatla 15587ae6478bSSrinivas Kandagatla kfree(cell); 155969aba794SSrinivas Kandagatla __nvmem_device_put(nvmem); 156069aba794SSrinivas Kandagatla } 156169aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_put); 156269aba794SSrinivas Kandagatla 15637ae6478bSSrinivas Kandagatla static void nvmem_shift_read_buffer_in_place(struct nvmem_cell_entry *cell, void *buf) 156469aba794SSrinivas Kandagatla { 156569aba794SSrinivas Kandagatla u8 *p, *b; 15662fe518feSJorge Ramirez-Ortiz int i, extra, bit_offset = cell->bit_offset; 156769aba794SSrinivas Kandagatla 156869aba794SSrinivas Kandagatla p = b = buf; 156969aba794SSrinivas Kandagatla if (bit_offset) { 157069aba794SSrinivas Kandagatla /* First shift */ 157169aba794SSrinivas Kandagatla *b++ >>= bit_offset; 157269aba794SSrinivas Kandagatla 157369aba794SSrinivas Kandagatla /* setup rest of the bytes if any */ 157469aba794SSrinivas Kandagatla for (i = 1; i < cell->bytes; i++) { 157569aba794SSrinivas Kandagatla /* Get bits from next byte and shift them towards msb */ 157669aba794SSrinivas Kandagatla *p |= *b << (BITS_PER_BYTE - bit_offset); 157769aba794SSrinivas Kandagatla 157869aba794SSrinivas Kandagatla p = b; 157969aba794SSrinivas Kandagatla *b++ >>= bit_offset; 158069aba794SSrinivas Kandagatla } 15812fe518feSJorge Ramirez-Ortiz } else { 15822fe518feSJorge Ramirez-Ortiz /* point to the msb */ 15832fe518feSJorge Ramirez-Ortiz p += cell->bytes - 1; 15842fe518feSJorge Ramirez-Ortiz } 158569aba794SSrinivas Kandagatla 158669aba794SSrinivas Kandagatla /* result fits in less bytes */ 15872fe518feSJorge Ramirez-Ortiz extra = cell->bytes - DIV_ROUND_UP(cell->nbits, BITS_PER_BYTE); 15882fe518feSJorge Ramirez-Ortiz while (--extra >= 0) 158969aba794SSrinivas Kandagatla *p-- = 0; 15902fe518feSJorge Ramirez-Ortiz 159169aba794SSrinivas Kandagatla /* clear msb bits if any leftover in the last byte */ 15925d388fa0SStephen Boyd if (cell->nbits % BITS_PER_BYTE) 159369aba794SSrinivas Kandagatla *p &= GENMASK((cell->nbits % BITS_PER_BYTE) - 1, 0); 159469aba794SSrinivas Kandagatla } 159569aba794SSrinivas Kandagatla 159669aba794SSrinivas Kandagatla static int __nvmem_cell_read(struct nvmem_device *nvmem, 15977ae6478bSSrinivas Kandagatla struct nvmem_cell_entry *cell, 15985d8e6e6cSMichael Walle void *buf, size_t *len, const char *id, int index) 159969aba794SSrinivas Kandagatla { 160069aba794SSrinivas Kandagatla int rc; 160169aba794SSrinivas Kandagatla 160255d4980cSRafał Miłecki rc = nvmem_reg_read(nvmem, cell->offset, buf, cell->raw_len); 160369aba794SSrinivas Kandagatla 1604287980e4SArnd Bergmann if (rc) 160569aba794SSrinivas Kandagatla return rc; 160669aba794SSrinivas Kandagatla 160769aba794SSrinivas Kandagatla /* shift bits in-place */ 1608cbf854abSAxel Lin if (cell->bit_offset || cell->nbits) 160969aba794SSrinivas Kandagatla nvmem_shift_read_buffer_in_place(cell, buf); 161069aba794SSrinivas Kandagatla 1611345ec382SMichael Walle if (cell->read_post_process) { 16128a134fd9SMichael Walle rc = cell->read_post_process(cell->priv, id, index, 161355d4980cSRafał Miłecki cell->offset, buf, cell->raw_len); 1614345ec382SMichael Walle if (rc) 1615345ec382SMichael Walle return rc; 1616345ec382SMichael Walle } 1617345ec382SMichael Walle 16183b4a6877SVivek Gautam if (len) 161969aba794SSrinivas Kandagatla *len = cell->bytes; 162069aba794SSrinivas Kandagatla 162169aba794SSrinivas Kandagatla return 0; 162269aba794SSrinivas Kandagatla } 162369aba794SSrinivas Kandagatla 162469aba794SSrinivas Kandagatla /** 162569aba794SSrinivas Kandagatla * nvmem_cell_read() - Read a given nvmem cell 162669aba794SSrinivas Kandagatla * 162769aba794SSrinivas Kandagatla * @cell: nvmem cell to be read. 16283b4a6877SVivek Gautam * @len: pointer to length of cell which will be populated on successful read; 16293b4a6877SVivek Gautam * can be NULL. 163069aba794SSrinivas Kandagatla * 1631b577fafcSBrian Norris * Return: ERR_PTR() on error or a valid pointer to a buffer on success. The 1632b577fafcSBrian Norris * buffer should be freed by the consumer with a kfree(). 163369aba794SSrinivas Kandagatla */ 163469aba794SSrinivas Kandagatla void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len) 163569aba794SSrinivas Kandagatla { 163655d4980cSRafał Miłecki struct nvmem_cell_entry *entry = cell->entry; 163755d4980cSRafał Miłecki struct nvmem_device *nvmem = entry->nvmem; 163869aba794SSrinivas Kandagatla u8 *buf; 163969aba794SSrinivas Kandagatla int rc; 164069aba794SSrinivas Kandagatla 1641795ddd18SSrinivas Kandagatla if (!nvmem) 164269aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 164369aba794SSrinivas Kandagatla 164455d4980cSRafał Miłecki buf = kzalloc(max_t(size_t, entry->raw_len, entry->bytes), GFP_KERNEL); 164569aba794SSrinivas Kandagatla if (!buf) 164669aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 164769aba794SSrinivas Kandagatla 16485d8e6e6cSMichael Walle rc = __nvmem_cell_read(nvmem, cell->entry, buf, len, cell->id, cell->index); 1649287980e4SArnd Bergmann if (rc) { 165069aba794SSrinivas Kandagatla kfree(buf); 165169aba794SSrinivas Kandagatla return ERR_PTR(rc); 165269aba794SSrinivas Kandagatla } 165369aba794SSrinivas Kandagatla 165469aba794SSrinivas Kandagatla return buf; 165569aba794SSrinivas Kandagatla } 165669aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_read); 165769aba794SSrinivas Kandagatla 16587ae6478bSSrinivas Kandagatla static void *nvmem_cell_prepare_write_buffer(struct nvmem_cell_entry *cell, 165969aba794SSrinivas Kandagatla u8 *_buf, int len) 166069aba794SSrinivas Kandagatla { 166169aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 166269aba794SSrinivas Kandagatla int i, rc, nbits, bit_offset = cell->bit_offset; 166369aba794SSrinivas Kandagatla u8 v, *p, *buf, *b, pbyte, pbits; 166469aba794SSrinivas Kandagatla 166569aba794SSrinivas Kandagatla nbits = cell->nbits; 166669aba794SSrinivas Kandagatla buf = kzalloc(cell->bytes, GFP_KERNEL); 166769aba794SSrinivas Kandagatla if (!buf) 166869aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 166969aba794SSrinivas Kandagatla 167069aba794SSrinivas Kandagatla memcpy(buf, _buf, len); 167169aba794SSrinivas Kandagatla p = b = buf; 167269aba794SSrinivas Kandagatla 167369aba794SSrinivas Kandagatla if (bit_offset) { 167469aba794SSrinivas Kandagatla pbyte = *b; 167569aba794SSrinivas Kandagatla *b <<= bit_offset; 167669aba794SSrinivas Kandagatla 167769aba794SSrinivas Kandagatla /* setup the first byte with lsb bits from nvmem */ 1678795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, cell->offset, &v, 1); 167950808bfcSMathieu Malaterre if (rc) 168050808bfcSMathieu Malaterre goto err; 168169aba794SSrinivas Kandagatla *b++ |= GENMASK(bit_offset - 1, 0) & v; 168269aba794SSrinivas Kandagatla 168369aba794SSrinivas Kandagatla /* setup rest of the byte if any */ 168469aba794SSrinivas Kandagatla for (i = 1; i < cell->bytes; i++) { 168569aba794SSrinivas Kandagatla /* Get last byte bits and shift them towards lsb */ 168669aba794SSrinivas Kandagatla pbits = pbyte >> (BITS_PER_BYTE - 1 - bit_offset); 168769aba794SSrinivas Kandagatla pbyte = *b; 168869aba794SSrinivas Kandagatla p = b; 168969aba794SSrinivas Kandagatla *b <<= bit_offset; 169069aba794SSrinivas Kandagatla *b++ |= pbits; 169169aba794SSrinivas Kandagatla } 169269aba794SSrinivas Kandagatla } 169369aba794SSrinivas Kandagatla 169469aba794SSrinivas Kandagatla /* if it's not end on byte boundary */ 169569aba794SSrinivas Kandagatla if ((nbits + bit_offset) % BITS_PER_BYTE) { 169669aba794SSrinivas Kandagatla /* setup the last byte with msb bits from nvmem */ 1697795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, 169869aba794SSrinivas Kandagatla cell->offset + cell->bytes - 1, &v, 1); 169950808bfcSMathieu Malaterre if (rc) 170050808bfcSMathieu Malaterre goto err; 170169aba794SSrinivas Kandagatla *p |= GENMASK(7, (nbits + bit_offset) % BITS_PER_BYTE) & v; 170269aba794SSrinivas Kandagatla 170369aba794SSrinivas Kandagatla } 170469aba794SSrinivas Kandagatla 170569aba794SSrinivas Kandagatla return buf; 170650808bfcSMathieu Malaterre err: 170750808bfcSMathieu Malaterre kfree(buf); 170850808bfcSMathieu Malaterre return ERR_PTR(rc); 170969aba794SSrinivas Kandagatla } 171069aba794SSrinivas Kandagatla 17117ae6478bSSrinivas Kandagatla static int __nvmem_cell_entry_write(struct nvmem_cell_entry *cell, void *buf, size_t len) 171269aba794SSrinivas Kandagatla { 171369aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 171469aba794SSrinivas Kandagatla int rc; 171569aba794SSrinivas Kandagatla 1716795ddd18SSrinivas Kandagatla if (!nvmem || nvmem->read_only || 171769aba794SSrinivas Kandagatla (cell->bit_offset == 0 && len != cell->bytes)) 171869aba794SSrinivas Kandagatla return -EINVAL; 171969aba794SSrinivas Kandagatla 1720345ec382SMichael Walle /* 1721345ec382SMichael Walle * Any cells which have a read_post_process hook are read-only because 1722345ec382SMichael Walle * we cannot reverse the operation and it might affect other cells, 1723345ec382SMichael Walle * too. 1724345ec382SMichael Walle */ 1725345ec382SMichael Walle if (cell->read_post_process) 1726345ec382SMichael Walle return -EINVAL; 1727345ec382SMichael Walle 172869aba794SSrinivas Kandagatla if (cell->bit_offset || cell->nbits) { 172969aba794SSrinivas Kandagatla buf = nvmem_cell_prepare_write_buffer(cell, buf, len); 173069aba794SSrinivas Kandagatla if (IS_ERR(buf)) 173169aba794SSrinivas Kandagatla return PTR_ERR(buf); 173269aba794SSrinivas Kandagatla } 173369aba794SSrinivas Kandagatla 1734795ddd18SSrinivas Kandagatla rc = nvmem_reg_write(nvmem, cell->offset, buf, cell->bytes); 173569aba794SSrinivas Kandagatla 173669aba794SSrinivas Kandagatla /* free the tmp buffer */ 1737ace22170SAxel Lin if (cell->bit_offset || cell->nbits) 173869aba794SSrinivas Kandagatla kfree(buf); 173969aba794SSrinivas Kandagatla 1740287980e4SArnd Bergmann if (rc) 174169aba794SSrinivas Kandagatla return rc; 174269aba794SSrinivas Kandagatla 174369aba794SSrinivas Kandagatla return len; 174469aba794SSrinivas Kandagatla } 17457ae6478bSSrinivas Kandagatla 17467ae6478bSSrinivas Kandagatla /** 17477ae6478bSSrinivas Kandagatla * nvmem_cell_write() - Write to a given nvmem cell 17487ae6478bSSrinivas Kandagatla * 17497ae6478bSSrinivas Kandagatla * @cell: nvmem cell to be written. 17507ae6478bSSrinivas Kandagatla * @buf: Buffer to be written. 17517ae6478bSSrinivas Kandagatla * @len: length of buffer to be written to nvmem cell. 17527ae6478bSSrinivas Kandagatla * 17537ae6478bSSrinivas Kandagatla * Return: length of bytes written or negative on failure. 17547ae6478bSSrinivas Kandagatla */ 17557ae6478bSSrinivas Kandagatla int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len) 17567ae6478bSSrinivas Kandagatla { 17577ae6478bSSrinivas Kandagatla return __nvmem_cell_entry_write(cell->entry, buf, len); 17587ae6478bSSrinivas Kandagatla } 17597ae6478bSSrinivas Kandagatla 176069aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_write); 176169aba794SSrinivas Kandagatla 17626bb317ceSYangtao Li static int nvmem_cell_read_common(struct device *dev, const char *cell_id, 17636bb317ceSYangtao Li void *val, size_t count) 17640a9b2d1cSFabrice Gasnier { 17650a9b2d1cSFabrice Gasnier struct nvmem_cell *cell; 17660a9b2d1cSFabrice Gasnier void *buf; 17670a9b2d1cSFabrice Gasnier size_t len; 17680a9b2d1cSFabrice Gasnier 17690a9b2d1cSFabrice Gasnier cell = nvmem_cell_get(dev, cell_id); 17700a9b2d1cSFabrice Gasnier if (IS_ERR(cell)) 17710a9b2d1cSFabrice Gasnier return PTR_ERR(cell); 17720a9b2d1cSFabrice Gasnier 17730a9b2d1cSFabrice Gasnier buf = nvmem_cell_read(cell, &len); 17740a9b2d1cSFabrice Gasnier if (IS_ERR(buf)) { 17750a9b2d1cSFabrice Gasnier nvmem_cell_put(cell); 17760a9b2d1cSFabrice Gasnier return PTR_ERR(buf); 17770a9b2d1cSFabrice Gasnier } 17786bb317ceSYangtao Li if (len != count) { 17790a9b2d1cSFabrice Gasnier kfree(buf); 17800a9b2d1cSFabrice Gasnier nvmem_cell_put(cell); 17810a9b2d1cSFabrice Gasnier return -EINVAL; 17820a9b2d1cSFabrice Gasnier } 17836bb317ceSYangtao Li memcpy(val, buf, count); 17840a9b2d1cSFabrice Gasnier kfree(buf); 17850a9b2d1cSFabrice Gasnier nvmem_cell_put(cell); 17860a9b2d1cSFabrice Gasnier 17870a9b2d1cSFabrice Gasnier return 0; 17880a9b2d1cSFabrice Gasnier } 17896bb317ceSYangtao Li 17906bb317ceSYangtao Li /** 17915037d368SAndreas Färber * nvmem_cell_read_u8() - Read a cell value as a u8 17925037d368SAndreas Färber * 17935037d368SAndreas Färber * @dev: Device that requests the nvmem cell. 17945037d368SAndreas Färber * @cell_id: Name of nvmem cell to read. 17955037d368SAndreas Färber * @val: pointer to output value. 17965037d368SAndreas Färber * 17975037d368SAndreas Färber * Return: 0 on success or negative errno. 17985037d368SAndreas Färber */ 17995037d368SAndreas Färber int nvmem_cell_read_u8(struct device *dev, const char *cell_id, u8 *val) 18005037d368SAndreas Färber { 18015037d368SAndreas Färber return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val)); 18025037d368SAndreas Färber } 18035037d368SAndreas Färber EXPORT_SYMBOL_GPL(nvmem_cell_read_u8); 18045037d368SAndreas Färber 18055037d368SAndreas Färber /** 18063a758071SAndreas Färber * nvmem_cell_read_u16() - Read a cell value as a u16 18076bb317ceSYangtao Li * 18086bb317ceSYangtao Li * @dev: Device that requests the nvmem cell. 18096bb317ceSYangtao Li * @cell_id: Name of nvmem cell to read. 18106bb317ceSYangtao Li * @val: pointer to output value. 18116bb317ceSYangtao Li * 18126bb317ceSYangtao Li * Return: 0 on success or negative errno. 18136bb317ceSYangtao Li */ 18146bb317ceSYangtao Li int nvmem_cell_read_u16(struct device *dev, const char *cell_id, u16 *val) 18156bb317ceSYangtao Li { 18166bb317ceSYangtao Li return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val)); 18176bb317ceSYangtao Li } 18180a9b2d1cSFabrice Gasnier EXPORT_SYMBOL_GPL(nvmem_cell_read_u16); 18190a9b2d1cSFabrice Gasnier 18200a9b2d1cSFabrice Gasnier /** 18213a758071SAndreas Färber * nvmem_cell_read_u32() - Read a cell value as a u32 1822d026d70aSLeonard Crestez * 1823d026d70aSLeonard Crestez * @dev: Device that requests the nvmem cell. 1824d026d70aSLeonard Crestez * @cell_id: Name of nvmem cell to read. 1825d026d70aSLeonard Crestez * @val: pointer to output value. 1826d026d70aSLeonard Crestez * 1827d026d70aSLeonard Crestez * Return: 0 on success or negative errno. 1828d026d70aSLeonard Crestez */ 1829d026d70aSLeonard Crestez int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val) 1830d026d70aSLeonard Crestez { 18316bb317ceSYangtao Li return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val)); 1832d026d70aSLeonard Crestez } 1833d026d70aSLeonard Crestez EXPORT_SYMBOL_GPL(nvmem_cell_read_u32); 1834d026d70aSLeonard Crestez 1835d026d70aSLeonard Crestez /** 18363a758071SAndreas Färber * nvmem_cell_read_u64() - Read a cell value as a u64 18378b977c54SYangtao Li * 18388b977c54SYangtao Li * @dev: Device that requests the nvmem cell. 18398b977c54SYangtao Li * @cell_id: Name of nvmem cell to read. 18408b977c54SYangtao Li * @val: pointer to output value. 18418b977c54SYangtao Li * 18428b977c54SYangtao Li * Return: 0 on success or negative errno. 18438b977c54SYangtao Li */ 18448b977c54SYangtao Li int nvmem_cell_read_u64(struct device *dev, const char *cell_id, u64 *val) 18458b977c54SYangtao Li { 18468b977c54SYangtao Li return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val)); 18478b977c54SYangtao Li } 18488b977c54SYangtao Li EXPORT_SYMBOL_GPL(nvmem_cell_read_u64); 18498b977c54SYangtao Li 18501f7b4d87SDouglas Anderson static const void *nvmem_cell_read_variable_common(struct device *dev, 1851a28e824fSDouglas Anderson const char *cell_id, 1852a28e824fSDouglas Anderson size_t max_len, size_t *len) 1853a28e824fSDouglas Anderson { 1854a28e824fSDouglas Anderson struct nvmem_cell *cell; 1855a28e824fSDouglas Anderson int nbits; 1856a28e824fSDouglas Anderson void *buf; 1857a28e824fSDouglas Anderson 1858a28e824fSDouglas Anderson cell = nvmem_cell_get(dev, cell_id); 1859a28e824fSDouglas Anderson if (IS_ERR(cell)) 1860a28e824fSDouglas Anderson return cell; 1861a28e824fSDouglas Anderson 18627ae6478bSSrinivas Kandagatla nbits = cell->entry->nbits; 1863a28e824fSDouglas Anderson buf = nvmem_cell_read(cell, len); 1864a28e824fSDouglas Anderson nvmem_cell_put(cell); 1865a28e824fSDouglas Anderson if (IS_ERR(buf)) 1866a28e824fSDouglas Anderson return buf; 1867a28e824fSDouglas Anderson 1868a28e824fSDouglas Anderson /* 1869a28e824fSDouglas Anderson * If nbits is set then nvmem_cell_read() can significantly exaggerate 1870a28e824fSDouglas Anderson * the length of the real data. Throw away the extra junk. 1871a28e824fSDouglas Anderson */ 1872a28e824fSDouglas Anderson if (nbits) 1873a28e824fSDouglas Anderson *len = DIV_ROUND_UP(nbits, 8); 1874a28e824fSDouglas Anderson 1875a28e824fSDouglas Anderson if (*len > max_len) { 1876a28e824fSDouglas Anderson kfree(buf); 1877a28e824fSDouglas Anderson return ERR_PTR(-ERANGE); 1878a28e824fSDouglas Anderson } 1879a28e824fSDouglas Anderson 1880a28e824fSDouglas Anderson return buf; 1881a28e824fSDouglas Anderson } 1882a28e824fSDouglas Anderson 1883a28e824fSDouglas Anderson /** 1884a28e824fSDouglas Anderson * nvmem_cell_read_variable_le_u32() - Read up to 32-bits of data as a little endian number. 1885a28e824fSDouglas Anderson * 1886a28e824fSDouglas Anderson * @dev: Device that requests the nvmem cell. 1887a28e824fSDouglas Anderson * @cell_id: Name of nvmem cell to read. 1888a28e824fSDouglas Anderson * @val: pointer to output value. 1889a28e824fSDouglas Anderson * 1890a28e824fSDouglas Anderson * Return: 0 on success or negative errno. 1891a28e824fSDouglas Anderson */ 1892a28e824fSDouglas Anderson int nvmem_cell_read_variable_le_u32(struct device *dev, const char *cell_id, 1893a28e824fSDouglas Anderson u32 *val) 1894a28e824fSDouglas Anderson { 1895a28e824fSDouglas Anderson size_t len; 18961f7b4d87SDouglas Anderson const u8 *buf; 1897a28e824fSDouglas Anderson int i; 1898a28e824fSDouglas Anderson 1899a28e824fSDouglas Anderson buf = nvmem_cell_read_variable_common(dev, cell_id, sizeof(*val), &len); 1900a28e824fSDouglas Anderson if (IS_ERR(buf)) 1901a28e824fSDouglas Anderson return PTR_ERR(buf); 1902a28e824fSDouglas Anderson 1903a28e824fSDouglas Anderson /* Copy w/ implicit endian conversion */ 1904a28e824fSDouglas Anderson *val = 0; 1905a28e824fSDouglas Anderson for (i = 0; i < len; i++) 1906a28e824fSDouglas Anderson *val |= buf[i] << (8 * i); 1907a28e824fSDouglas Anderson 1908a28e824fSDouglas Anderson kfree(buf); 1909a28e824fSDouglas Anderson 1910a28e824fSDouglas Anderson return 0; 1911a28e824fSDouglas Anderson } 1912a28e824fSDouglas Anderson EXPORT_SYMBOL_GPL(nvmem_cell_read_variable_le_u32); 1913a28e824fSDouglas Anderson 1914a28e824fSDouglas Anderson /** 1915a28e824fSDouglas Anderson * nvmem_cell_read_variable_le_u64() - Read up to 64-bits of data as a little endian number. 1916a28e824fSDouglas Anderson * 1917a28e824fSDouglas Anderson * @dev: Device that requests the nvmem cell. 1918a28e824fSDouglas Anderson * @cell_id: Name of nvmem cell to read. 1919a28e824fSDouglas Anderson * @val: pointer to output value. 1920a28e824fSDouglas Anderson * 1921a28e824fSDouglas Anderson * Return: 0 on success or negative errno. 1922a28e824fSDouglas Anderson */ 1923a28e824fSDouglas Anderson int nvmem_cell_read_variable_le_u64(struct device *dev, const char *cell_id, 1924a28e824fSDouglas Anderson u64 *val) 1925a28e824fSDouglas Anderson { 1926a28e824fSDouglas Anderson size_t len; 19271f7b4d87SDouglas Anderson const u8 *buf; 1928a28e824fSDouglas Anderson int i; 1929a28e824fSDouglas Anderson 1930a28e824fSDouglas Anderson buf = nvmem_cell_read_variable_common(dev, cell_id, sizeof(*val), &len); 1931a28e824fSDouglas Anderson if (IS_ERR(buf)) 1932a28e824fSDouglas Anderson return PTR_ERR(buf); 1933a28e824fSDouglas Anderson 1934a28e824fSDouglas Anderson /* Copy w/ implicit endian conversion */ 1935a28e824fSDouglas Anderson *val = 0; 1936a28e824fSDouglas Anderson for (i = 0; i < len; i++) 193755022fdeSColin Ian King *val |= (uint64_t)buf[i] << (8 * i); 1938a28e824fSDouglas Anderson 1939a28e824fSDouglas Anderson kfree(buf); 1940a28e824fSDouglas Anderson 1941a28e824fSDouglas Anderson return 0; 1942a28e824fSDouglas Anderson } 1943a28e824fSDouglas Anderson EXPORT_SYMBOL_GPL(nvmem_cell_read_variable_le_u64); 1944a28e824fSDouglas Anderson 19458b977c54SYangtao Li /** 1946e2a5402eSSrinivas Kandagatla * nvmem_device_cell_read() - Read a given nvmem device and cell 1947e2a5402eSSrinivas Kandagatla * 1948e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to read from. 1949e2a5402eSSrinivas Kandagatla * @info: nvmem cell info to be read. 1950e2a5402eSSrinivas Kandagatla * @buf: buffer pointer which will be populated on successful read. 1951e2a5402eSSrinivas Kandagatla * 1952e2a5402eSSrinivas Kandagatla * Return: length of successful bytes read on success and negative 1953e2a5402eSSrinivas Kandagatla * error code on error. 1954e2a5402eSSrinivas Kandagatla */ 1955e2a5402eSSrinivas Kandagatla ssize_t nvmem_device_cell_read(struct nvmem_device *nvmem, 1956e2a5402eSSrinivas Kandagatla struct nvmem_cell_info *info, void *buf) 1957e2a5402eSSrinivas Kandagatla { 19587ae6478bSSrinivas Kandagatla struct nvmem_cell_entry cell; 1959e2a5402eSSrinivas Kandagatla int rc; 1960e2a5402eSSrinivas Kandagatla ssize_t len; 1961e2a5402eSSrinivas Kandagatla 1962795ddd18SSrinivas Kandagatla if (!nvmem) 1963e2a5402eSSrinivas Kandagatla return -EINVAL; 1964e2a5402eSSrinivas Kandagatla 19657ae6478bSSrinivas Kandagatla rc = nvmem_cell_info_to_nvmem_cell_entry_nodup(nvmem, info, &cell); 1966287980e4SArnd Bergmann if (rc) 1967e2a5402eSSrinivas Kandagatla return rc; 1968e2a5402eSSrinivas Kandagatla 19695d8e6e6cSMichael Walle rc = __nvmem_cell_read(nvmem, &cell, buf, &len, NULL, 0); 1970287980e4SArnd Bergmann if (rc) 1971e2a5402eSSrinivas Kandagatla return rc; 1972e2a5402eSSrinivas Kandagatla 1973e2a5402eSSrinivas Kandagatla return len; 1974e2a5402eSSrinivas Kandagatla } 1975e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_cell_read); 1976e2a5402eSSrinivas Kandagatla 1977e2a5402eSSrinivas Kandagatla /** 1978e2a5402eSSrinivas Kandagatla * nvmem_device_cell_write() - Write cell to a given nvmem device 1979e2a5402eSSrinivas Kandagatla * 1980e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to be written to. 198129143268SVivek Gautam * @info: nvmem cell info to be written. 1982e2a5402eSSrinivas Kandagatla * @buf: buffer to be written to cell. 1983e2a5402eSSrinivas Kandagatla * 1984e2a5402eSSrinivas Kandagatla * Return: length of bytes written or negative error code on failure. 198548f63a2cSBartosz Golaszewski */ 1986e2a5402eSSrinivas Kandagatla int nvmem_device_cell_write(struct nvmem_device *nvmem, 1987e2a5402eSSrinivas Kandagatla struct nvmem_cell_info *info, void *buf) 1988e2a5402eSSrinivas Kandagatla { 19897ae6478bSSrinivas Kandagatla struct nvmem_cell_entry cell; 1990e2a5402eSSrinivas Kandagatla int rc; 1991e2a5402eSSrinivas Kandagatla 1992795ddd18SSrinivas Kandagatla if (!nvmem) 1993e2a5402eSSrinivas Kandagatla return -EINVAL; 1994e2a5402eSSrinivas Kandagatla 19957ae6478bSSrinivas Kandagatla rc = nvmem_cell_info_to_nvmem_cell_entry_nodup(nvmem, info, &cell); 1996287980e4SArnd Bergmann if (rc) 1997e2a5402eSSrinivas Kandagatla return rc; 1998e2a5402eSSrinivas Kandagatla 19997ae6478bSSrinivas Kandagatla return __nvmem_cell_entry_write(&cell, buf, cell.bytes); 2000e2a5402eSSrinivas Kandagatla } 2001e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_cell_write); 2002e2a5402eSSrinivas Kandagatla 2003e2a5402eSSrinivas Kandagatla /** 2004e2a5402eSSrinivas Kandagatla * nvmem_device_read() - Read from a given nvmem device 2005e2a5402eSSrinivas Kandagatla * 2006e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to read from. 2007e2a5402eSSrinivas Kandagatla * @offset: offset in nvmem device. 2008e2a5402eSSrinivas Kandagatla * @bytes: number of bytes to read. 2009e2a5402eSSrinivas Kandagatla * @buf: buffer pointer which will be populated on successful read. 2010e2a5402eSSrinivas Kandagatla * 2011e2a5402eSSrinivas Kandagatla * Return: length of successful bytes read on success and negative 2012e2a5402eSSrinivas Kandagatla * error code on error. 2013e2a5402eSSrinivas Kandagatla */ 2014e2a5402eSSrinivas Kandagatla int nvmem_device_read(struct nvmem_device *nvmem, 2015e2a5402eSSrinivas Kandagatla unsigned int offset, 2016e2a5402eSSrinivas Kandagatla size_t bytes, void *buf) 2017e2a5402eSSrinivas Kandagatla { 2018e2a5402eSSrinivas Kandagatla int rc; 2019e2a5402eSSrinivas Kandagatla 2020795ddd18SSrinivas Kandagatla if (!nvmem) 2021e2a5402eSSrinivas Kandagatla return -EINVAL; 2022e2a5402eSSrinivas Kandagatla 2023795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, offset, buf, bytes); 2024e2a5402eSSrinivas Kandagatla 2025287980e4SArnd Bergmann if (rc) 2026e2a5402eSSrinivas Kandagatla return rc; 2027e2a5402eSSrinivas Kandagatla 2028e2a5402eSSrinivas Kandagatla return bytes; 2029e2a5402eSSrinivas Kandagatla } 2030e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_read); 2031e2a5402eSSrinivas Kandagatla 2032e2a5402eSSrinivas Kandagatla /** 2033e2a5402eSSrinivas Kandagatla * nvmem_device_write() - Write cell to a given nvmem device 2034e2a5402eSSrinivas Kandagatla * 2035e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to be written to. 2036e2a5402eSSrinivas Kandagatla * @offset: offset in nvmem device. 2037e2a5402eSSrinivas Kandagatla * @bytes: number of bytes to write. 2038e2a5402eSSrinivas Kandagatla * @buf: buffer to be written. 2039e2a5402eSSrinivas Kandagatla * 2040e2a5402eSSrinivas Kandagatla * Return: length of bytes written or negative error code on failure. 204148f63a2cSBartosz Golaszewski */ 2042e2a5402eSSrinivas Kandagatla int nvmem_device_write(struct nvmem_device *nvmem, 2043e2a5402eSSrinivas Kandagatla unsigned int offset, 2044e2a5402eSSrinivas Kandagatla size_t bytes, void *buf) 2045e2a5402eSSrinivas Kandagatla { 2046e2a5402eSSrinivas Kandagatla int rc; 2047e2a5402eSSrinivas Kandagatla 2048795ddd18SSrinivas Kandagatla if (!nvmem) 2049e2a5402eSSrinivas Kandagatla return -EINVAL; 2050e2a5402eSSrinivas Kandagatla 2051795ddd18SSrinivas Kandagatla rc = nvmem_reg_write(nvmem, offset, buf, bytes); 2052e2a5402eSSrinivas Kandagatla 2053287980e4SArnd Bergmann if (rc) 2054e2a5402eSSrinivas Kandagatla return rc; 2055e2a5402eSSrinivas Kandagatla 2056e2a5402eSSrinivas Kandagatla 2057e2a5402eSSrinivas Kandagatla return bytes; 2058e2a5402eSSrinivas Kandagatla } 2059e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_write); 2060e2a5402eSSrinivas Kandagatla 2061d7b9fd16SBartosz Golaszewski /** 2062b985f4cbSBartosz Golaszewski * nvmem_add_cell_table() - register a table of cell info entries 2063b985f4cbSBartosz Golaszewski * 2064b985f4cbSBartosz Golaszewski * @table: table of cell info entries 2065b985f4cbSBartosz Golaszewski */ 2066b985f4cbSBartosz Golaszewski void nvmem_add_cell_table(struct nvmem_cell_table *table) 2067b985f4cbSBartosz Golaszewski { 2068b985f4cbSBartosz Golaszewski mutex_lock(&nvmem_cell_mutex); 2069b985f4cbSBartosz Golaszewski list_add_tail(&table->node, &nvmem_cell_tables); 2070b985f4cbSBartosz Golaszewski mutex_unlock(&nvmem_cell_mutex); 2071b985f4cbSBartosz Golaszewski } 2072b985f4cbSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_add_cell_table); 2073b985f4cbSBartosz Golaszewski 2074b985f4cbSBartosz Golaszewski /** 2075b985f4cbSBartosz Golaszewski * nvmem_del_cell_table() - remove a previously registered cell info table 2076b985f4cbSBartosz Golaszewski * 2077b985f4cbSBartosz Golaszewski * @table: table of cell info entries 2078b985f4cbSBartosz Golaszewski */ 2079b985f4cbSBartosz Golaszewski void nvmem_del_cell_table(struct nvmem_cell_table *table) 2080b985f4cbSBartosz Golaszewski { 2081b985f4cbSBartosz Golaszewski mutex_lock(&nvmem_cell_mutex); 2082b985f4cbSBartosz Golaszewski list_del(&table->node); 2083b985f4cbSBartosz Golaszewski mutex_unlock(&nvmem_cell_mutex); 2084b985f4cbSBartosz Golaszewski } 2085b985f4cbSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_del_cell_table); 2086b985f4cbSBartosz Golaszewski 2087b985f4cbSBartosz Golaszewski /** 2088506157beSBartosz Golaszewski * nvmem_add_cell_lookups() - register a list of cell lookup entries 2089506157beSBartosz Golaszewski * 2090506157beSBartosz Golaszewski * @entries: array of cell lookup entries 2091506157beSBartosz Golaszewski * @nentries: number of cell lookup entries in the array 2092506157beSBartosz Golaszewski */ 2093506157beSBartosz Golaszewski void nvmem_add_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries) 2094506157beSBartosz Golaszewski { 2095506157beSBartosz Golaszewski int i; 2096506157beSBartosz Golaszewski 2097506157beSBartosz Golaszewski mutex_lock(&nvmem_lookup_mutex); 2098506157beSBartosz Golaszewski for (i = 0; i < nentries; i++) 2099506157beSBartosz Golaszewski list_add_tail(&entries[i].node, &nvmem_lookup_list); 2100506157beSBartosz Golaszewski mutex_unlock(&nvmem_lookup_mutex); 2101506157beSBartosz Golaszewski } 2102506157beSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_add_cell_lookups); 2103506157beSBartosz Golaszewski 2104506157beSBartosz Golaszewski /** 2105506157beSBartosz Golaszewski * nvmem_del_cell_lookups() - remove a list of previously added cell lookup 2106506157beSBartosz Golaszewski * entries 2107506157beSBartosz Golaszewski * 2108506157beSBartosz Golaszewski * @entries: array of cell lookup entries 2109506157beSBartosz Golaszewski * @nentries: number of cell lookup entries in the array 2110506157beSBartosz Golaszewski */ 2111506157beSBartosz Golaszewski void nvmem_del_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries) 2112506157beSBartosz Golaszewski { 2113506157beSBartosz Golaszewski int i; 2114506157beSBartosz Golaszewski 2115506157beSBartosz Golaszewski mutex_lock(&nvmem_lookup_mutex); 2116506157beSBartosz Golaszewski for (i = 0; i < nentries; i++) 2117506157beSBartosz Golaszewski list_del(&entries[i].node); 2118506157beSBartosz Golaszewski mutex_unlock(&nvmem_lookup_mutex); 2119506157beSBartosz Golaszewski } 2120506157beSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_del_cell_lookups); 2121506157beSBartosz Golaszewski 2122506157beSBartosz Golaszewski /** 2123d7b9fd16SBartosz Golaszewski * nvmem_dev_name() - Get the name of a given nvmem device. 2124d7b9fd16SBartosz Golaszewski * 2125d7b9fd16SBartosz Golaszewski * @nvmem: nvmem device. 2126d7b9fd16SBartosz Golaszewski * 2127d7b9fd16SBartosz Golaszewski * Return: name of the nvmem device. 2128d7b9fd16SBartosz Golaszewski */ 2129d7b9fd16SBartosz Golaszewski const char *nvmem_dev_name(struct nvmem_device *nvmem) 2130d7b9fd16SBartosz Golaszewski { 2131d7b9fd16SBartosz Golaszewski return dev_name(&nvmem->dev); 2132d7b9fd16SBartosz Golaszewski } 2133d7b9fd16SBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_dev_name); 2134d7b9fd16SBartosz Golaszewski 2135eace75cfSSrinivas Kandagatla static int __init nvmem_init(void) 2136eace75cfSSrinivas Kandagatla { 2137eace75cfSSrinivas Kandagatla return bus_register(&nvmem_bus_type); 2138eace75cfSSrinivas Kandagatla } 2139eace75cfSSrinivas Kandagatla 2140eace75cfSSrinivas Kandagatla static void __exit nvmem_exit(void) 2141eace75cfSSrinivas Kandagatla { 2142eace75cfSSrinivas Kandagatla bus_unregister(&nvmem_bus_type); 2143eace75cfSSrinivas Kandagatla } 2144eace75cfSSrinivas Kandagatla 2145eace75cfSSrinivas Kandagatla subsys_initcall(nvmem_init); 2146eace75cfSSrinivas Kandagatla module_exit(nvmem_exit); 2147eace75cfSSrinivas Kandagatla 2148eace75cfSSrinivas Kandagatla MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org"); 2149eace75cfSSrinivas Kandagatla MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com"); 2150eace75cfSSrinivas Kandagatla MODULE_DESCRIPTION("nvmem Driver Core"); 2151