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 22*ec9c08a1SMiquel Raynal #include "internals.h" 2384400305SSrinivas Kandagatla 2484400305SSrinivas Kandagatla #define to_nvmem_device(d) container_of(d, struct nvmem_device, dev) 2584400305SSrinivas Kandagatla 2684400305SSrinivas Kandagatla #define FLAG_COMPAT BIT(0) 277ae6478bSSrinivas Kandagatla struct nvmem_cell_entry { 28eace75cfSSrinivas Kandagatla const char *name; 29eace75cfSSrinivas Kandagatla int offset; 3055d4980cSRafał Miłecki size_t raw_len; 31eace75cfSSrinivas Kandagatla int bytes; 32eace75cfSSrinivas Kandagatla int bit_offset; 33eace75cfSSrinivas Kandagatla int nbits; 34345ec382SMichael Walle nvmem_cell_post_process_t read_post_process; 358a134fd9SMichael Walle void *priv; 360749aa25SSrinivas Kandagatla struct device_node *np; 37eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem; 38eace75cfSSrinivas Kandagatla struct list_head node; 39eace75cfSSrinivas Kandagatla }; 40eace75cfSSrinivas Kandagatla 417ae6478bSSrinivas Kandagatla struct nvmem_cell { 427ae6478bSSrinivas Kandagatla struct nvmem_cell_entry *entry; 437ae6478bSSrinivas Kandagatla const char *id; 445d8e6e6cSMichael Walle int index; 457ae6478bSSrinivas Kandagatla }; 467ae6478bSSrinivas Kandagatla 47eace75cfSSrinivas Kandagatla static DEFINE_MUTEX(nvmem_mutex); 48eace75cfSSrinivas Kandagatla static DEFINE_IDA(nvmem_ida); 49eace75cfSSrinivas Kandagatla 50b985f4cbSBartosz Golaszewski static DEFINE_MUTEX(nvmem_cell_mutex); 51b985f4cbSBartosz Golaszewski static LIST_HEAD(nvmem_cell_tables); 52b985f4cbSBartosz Golaszewski 53506157beSBartosz Golaszewski static DEFINE_MUTEX(nvmem_lookup_mutex); 54506157beSBartosz Golaszewski static LIST_HEAD(nvmem_lookup_list); 55506157beSBartosz Golaszewski 56bee1138bSBartosz Golaszewski static BLOCKING_NOTIFIER_HEAD(nvmem_notifier); 57bee1138bSBartosz Golaszewski 58266570f4SMichael Walle static DEFINE_SPINLOCK(nvmem_layout_lock); 59266570f4SMichael Walle static LIST_HEAD(nvmem_layouts); 60266570f4SMichael Walle 61fd3bb8f5SEvan Green static int __nvmem_reg_read(struct nvmem_device *nvmem, unsigned int offset, 62b96fc541SMichael Auchter void *val, size_t bytes) 63b96fc541SMichael Auchter { 64b96fc541SMichael Auchter if (nvmem->reg_read) 65b96fc541SMichael Auchter return nvmem->reg_read(nvmem->priv, offset, val, bytes); 66b96fc541SMichael Auchter 67b96fc541SMichael Auchter return -EINVAL; 68b96fc541SMichael Auchter } 69b96fc541SMichael Auchter 70fd3bb8f5SEvan Green static int __nvmem_reg_write(struct nvmem_device *nvmem, unsigned int offset, 71b96fc541SMichael Auchter void *val, size_t bytes) 72b96fc541SMichael Auchter { 73b96fc541SMichael Auchter int ret; 74b96fc541SMichael Auchter 75b96fc541SMichael Auchter if (nvmem->reg_write) { 76b96fc541SMichael Auchter gpiod_set_value_cansleep(nvmem->wp_gpio, 0); 77b96fc541SMichael Auchter ret = nvmem->reg_write(nvmem->priv, offset, val, bytes); 78b96fc541SMichael Auchter gpiod_set_value_cansleep(nvmem->wp_gpio, 1); 79b96fc541SMichael Auchter return ret; 80b96fc541SMichael Auchter } 81b96fc541SMichael Auchter 82b96fc541SMichael Auchter return -EINVAL; 83b96fc541SMichael Auchter } 84b96fc541SMichael Auchter 85fd3bb8f5SEvan Green static int nvmem_access_with_keepouts(struct nvmem_device *nvmem, 86fd3bb8f5SEvan Green unsigned int offset, void *val, 87fd3bb8f5SEvan Green size_t bytes, int write) 88fd3bb8f5SEvan Green { 89fd3bb8f5SEvan Green 90fd3bb8f5SEvan Green unsigned int end = offset + bytes; 91fd3bb8f5SEvan Green unsigned int kend, ksize; 92fd3bb8f5SEvan Green const struct nvmem_keepout *keepout = nvmem->keepout; 93fd3bb8f5SEvan Green const struct nvmem_keepout *keepoutend = keepout + nvmem->nkeepout; 94fd3bb8f5SEvan Green int rc; 95fd3bb8f5SEvan Green 96fd3bb8f5SEvan Green /* 97fd3bb8f5SEvan Green * Skip all keepouts before the range being accessed. 98fd3bb8f5SEvan Green * Keepouts are sorted. 99fd3bb8f5SEvan Green */ 100fd3bb8f5SEvan Green while ((keepout < keepoutend) && (keepout->end <= offset)) 101fd3bb8f5SEvan Green keepout++; 102fd3bb8f5SEvan Green 103fd3bb8f5SEvan Green while ((offset < end) && (keepout < keepoutend)) { 104fd3bb8f5SEvan Green /* Access the valid portion before the keepout. */ 105fd3bb8f5SEvan Green if (offset < keepout->start) { 106fd3bb8f5SEvan Green kend = min(end, keepout->start); 107fd3bb8f5SEvan Green ksize = kend - offset; 108fd3bb8f5SEvan Green if (write) 109fd3bb8f5SEvan Green rc = __nvmem_reg_write(nvmem, offset, val, ksize); 110fd3bb8f5SEvan Green else 111fd3bb8f5SEvan Green rc = __nvmem_reg_read(nvmem, offset, val, ksize); 112fd3bb8f5SEvan Green 113fd3bb8f5SEvan Green if (rc) 114fd3bb8f5SEvan Green return rc; 115fd3bb8f5SEvan Green 116fd3bb8f5SEvan Green offset += ksize; 117fd3bb8f5SEvan Green val += ksize; 118fd3bb8f5SEvan Green } 119fd3bb8f5SEvan Green 120fd3bb8f5SEvan Green /* 121fd3bb8f5SEvan Green * Now we're aligned to the start of this keepout zone. Go 122fd3bb8f5SEvan Green * through it. 123fd3bb8f5SEvan Green */ 124fd3bb8f5SEvan Green kend = min(end, keepout->end); 125fd3bb8f5SEvan Green ksize = kend - offset; 126fd3bb8f5SEvan Green if (!write) 127fd3bb8f5SEvan Green memset(val, keepout->value, ksize); 128fd3bb8f5SEvan Green 129fd3bb8f5SEvan Green val += ksize; 130fd3bb8f5SEvan Green offset += ksize; 131fd3bb8f5SEvan Green keepout++; 132fd3bb8f5SEvan Green } 133fd3bb8f5SEvan Green 134fd3bb8f5SEvan Green /* 135fd3bb8f5SEvan Green * If we ran out of keepouts but there's still stuff to do, send it 136fd3bb8f5SEvan Green * down directly 137fd3bb8f5SEvan Green */ 138fd3bb8f5SEvan Green if (offset < end) { 139fd3bb8f5SEvan Green ksize = end - offset; 140fd3bb8f5SEvan Green if (write) 141fd3bb8f5SEvan Green return __nvmem_reg_write(nvmem, offset, val, ksize); 142fd3bb8f5SEvan Green else 143fd3bb8f5SEvan Green return __nvmem_reg_read(nvmem, offset, val, ksize); 144fd3bb8f5SEvan Green } 145fd3bb8f5SEvan Green 146fd3bb8f5SEvan Green return 0; 147fd3bb8f5SEvan Green } 148fd3bb8f5SEvan Green 149fd3bb8f5SEvan Green static int nvmem_reg_read(struct nvmem_device *nvmem, unsigned int offset, 150fd3bb8f5SEvan Green void *val, size_t bytes) 151fd3bb8f5SEvan Green { 152fd3bb8f5SEvan Green if (!nvmem->nkeepout) 153fd3bb8f5SEvan Green return __nvmem_reg_read(nvmem, offset, val, bytes); 154fd3bb8f5SEvan Green 155fd3bb8f5SEvan Green return nvmem_access_with_keepouts(nvmem, offset, val, bytes, false); 156fd3bb8f5SEvan Green } 157fd3bb8f5SEvan Green 158fd3bb8f5SEvan Green static int nvmem_reg_write(struct nvmem_device *nvmem, unsigned int offset, 159fd3bb8f5SEvan Green void *val, size_t bytes) 160fd3bb8f5SEvan Green { 161fd3bb8f5SEvan Green if (!nvmem->nkeepout) 162fd3bb8f5SEvan Green return __nvmem_reg_write(nvmem, offset, val, bytes); 163fd3bb8f5SEvan Green 164fd3bb8f5SEvan Green return nvmem_access_with_keepouts(nvmem, offset, val, bytes, true); 165fd3bb8f5SEvan Green } 166fd3bb8f5SEvan Green 16784400305SSrinivas Kandagatla #ifdef CONFIG_NVMEM_SYSFS 16884400305SSrinivas Kandagatla static const char * const nvmem_type_str[] = { 16984400305SSrinivas Kandagatla [NVMEM_TYPE_UNKNOWN] = "Unknown", 17084400305SSrinivas Kandagatla [NVMEM_TYPE_EEPROM] = "EEPROM", 17184400305SSrinivas Kandagatla [NVMEM_TYPE_OTP] = "OTP", 17284400305SSrinivas Kandagatla [NVMEM_TYPE_BATTERY_BACKED] = "Battery backed", 173fd307a4aSJiri Prchal [NVMEM_TYPE_FRAM] = "FRAM", 17484400305SSrinivas Kandagatla }; 17584400305SSrinivas Kandagatla 17684400305SSrinivas Kandagatla #ifdef CONFIG_DEBUG_LOCK_ALLOC 17784400305SSrinivas Kandagatla static struct lock_class_key eeprom_lock_key; 17884400305SSrinivas Kandagatla #endif 17984400305SSrinivas Kandagatla 18084400305SSrinivas Kandagatla static ssize_t type_show(struct device *dev, 18184400305SSrinivas Kandagatla struct device_attribute *attr, char *buf) 18284400305SSrinivas Kandagatla { 18384400305SSrinivas Kandagatla struct nvmem_device *nvmem = to_nvmem_device(dev); 18484400305SSrinivas Kandagatla 18584400305SSrinivas Kandagatla return sprintf(buf, "%s\n", nvmem_type_str[nvmem->type]); 18684400305SSrinivas Kandagatla } 18784400305SSrinivas Kandagatla 18884400305SSrinivas Kandagatla static DEVICE_ATTR_RO(type); 18984400305SSrinivas Kandagatla 19084400305SSrinivas Kandagatla static struct attribute *nvmem_attrs[] = { 19184400305SSrinivas Kandagatla &dev_attr_type.attr, 19284400305SSrinivas Kandagatla NULL, 19384400305SSrinivas Kandagatla }; 19484400305SSrinivas Kandagatla 19584400305SSrinivas Kandagatla static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj, 19684400305SSrinivas Kandagatla struct bin_attribute *attr, char *buf, 19784400305SSrinivas Kandagatla loff_t pos, size_t count) 19884400305SSrinivas Kandagatla { 19984400305SSrinivas Kandagatla struct device *dev; 20084400305SSrinivas Kandagatla struct nvmem_device *nvmem; 20184400305SSrinivas Kandagatla int rc; 20284400305SSrinivas Kandagatla 20384400305SSrinivas Kandagatla if (attr->private) 20484400305SSrinivas Kandagatla dev = attr->private; 20584400305SSrinivas Kandagatla else 20628371cc6STian Tao dev = kobj_to_dev(kobj); 20784400305SSrinivas Kandagatla nvmem = to_nvmem_device(dev); 20884400305SSrinivas Kandagatla 20984400305SSrinivas Kandagatla /* Stop the user from reading */ 21084400305SSrinivas Kandagatla if (pos >= nvmem->size) 21184400305SSrinivas Kandagatla return 0; 21284400305SSrinivas Kandagatla 21383566715SDouglas Anderson if (!IS_ALIGNED(pos, nvmem->stride)) 21483566715SDouglas Anderson return -EINVAL; 21583566715SDouglas Anderson 21684400305SSrinivas Kandagatla if (count < nvmem->word_size) 21784400305SSrinivas Kandagatla return -EINVAL; 21884400305SSrinivas Kandagatla 21984400305SSrinivas Kandagatla if (pos + count > nvmem->size) 22084400305SSrinivas Kandagatla count = nvmem->size - pos; 22184400305SSrinivas Kandagatla 22284400305SSrinivas Kandagatla count = round_down(count, nvmem->word_size); 22384400305SSrinivas Kandagatla 22484400305SSrinivas Kandagatla if (!nvmem->reg_read) 22584400305SSrinivas Kandagatla return -EPERM; 22684400305SSrinivas Kandagatla 227b96fc541SMichael Auchter rc = nvmem_reg_read(nvmem, pos, buf, count); 22884400305SSrinivas Kandagatla 22984400305SSrinivas Kandagatla if (rc) 23084400305SSrinivas Kandagatla return rc; 23184400305SSrinivas Kandagatla 23284400305SSrinivas Kandagatla return count; 23384400305SSrinivas Kandagatla } 23484400305SSrinivas Kandagatla 23584400305SSrinivas Kandagatla static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj, 23684400305SSrinivas Kandagatla struct bin_attribute *attr, char *buf, 23784400305SSrinivas Kandagatla loff_t pos, size_t count) 23884400305SSrinivas Kandagatla { 23984400305SSrinivas Kandagatla struct device *dev; 24084400305SSrinivas Kandagatla struct nvmem_device *nvmem; 24184400305SSrinivas Kandagatla int rc; 24284400305SSrinivas Kandagatla 24384400305SSrinivas Kandagatla if (attr->private) 24484400305SSrinivas Kandagatla dev = attr->private; 24584400305SSrinivas Kandagatla else 24628371cc6STian Tao dev = kobj_to_dev(kobj); 24784400305SSrinivas Kandagatla nvmem = to_nvmem_device(dev); 24884400305SSrinivas Kandagatla 24984400305SSrinivas Kandagatla /* Stop the user from writing */ 25084400305SSrinivas Kandagatla if (pos >= nvmem->size) 25184400305SSrinivas Kandagatla return -EFBIG; 25284400305SSrinivas Kandagatla 25383566715SDouglas Anderson if (!IS_ALIGNED(pos, nvmem->stride)) 25483566715SDouglas Anderson return -EINVAL; 25583566715SDouglas Anderson 25684400305SSrinivas Kandagatla if (count < nvmem->word_size) 25784400305SSrinivas Kandagatla return -EINVAL; 25884400305SSrinivas Kandagatla 25984400305SSrinivas Kandagatla if (pos + count > nvmem->size) 26084400305SSrinivas Kandagatla count = nvmem->size - pos; 26184400305SSrinivas Kandagatla 26284400305SSrinivas Kandagatla count = round_down(count, nvmem->word_size); 26384400305SSrinivas Kandagatla 26484400305SSrinivas Kandagatla if (!nvmem->reg_write) 26584400305SSrinivas Kandagatla return -EPERM; 26684400305SSrinivas Kandagatla 267b96fc541SMichael Auchter rc = nvmem_reg_write(nvmem, pos, buf, count); 26884400305SSrinivas Kandagatla 26984400305SSrinivas Kandagatla if (rc) 27084400305SSrinivas Kandagatla return rc; 27184400305SSrinivas Kandagatla 27284400305SSrinivas Kandagatla return count; 27384400305SSrinivas Kandagatla } 27484400305SSrinivas Kandagatla 2752a4542e5SSrinivas Kandagatla static umode_t nvmem_bin_attr_get_umode(struct nvmem_device *nvmem) 27684400305SSrinivas Kandagatla { 27784400305SSrinivas Kandagatla umode_t mode = 0400; 27884400305SSrinivas Kandagatla 27984400305SSrinivas Kandagatla if (!nvmem->root_only) 28084400305SSrinivas Kandagatla mode |= 0044; 28184400305SSrinivas Kandagatla 28284400305SSrinivas Kandagatla if (!nvmem->read_only) 28384400305SSrinivas Kandagatla mode |= 0200; 28484400305SSrinivas Kandagatla 28584400305SSrinivas Kandagatla if (!nvmem->reg_write) 28684400305SSrinivas Kandagatla mode &= ~0200; 28784400305SSrinivas Kandagatla 28884400305SSrinivas Kandagatla if (!nvmem->reg_read) 28984400305SSrinivas Kandagatla mode &= ~0444; 29084400305SSrinivas Kandagatla 29184400305SSrinivas Kandagatla return mode; 29284400305SSrinivas Kandagatla } 29384400305SSrinivas Kandagatla 2942a4542e5SSrinivas Kandagatla static umode_t nvmem_bin_attr_is_visible(struct kobject *kobj, 2952a4542e5SSrinivas Kandagatla struct bin_attribute *attr, int i) 2962a4542e5SSrinivas Kandagatla { 29728371cc6STian Tao struct device *dev = kobj_to_dev(kobj); 2982a4542e5SSrinivas Kandagatla struct nvmem_device *nvmem = to_nvmem_device(dev); 2992a4542e5SSrinivas Kandagatla 30086192251SSrinivas Kandagatla attr->size = nvmem->size; 30186192251SSrinivas Kandagatla 3022a4542e5SSrinivas Kandagatla return nvmem_bin_attr_get_umode(nvmem); 3032a4542e5SSrinivas Kandagatla } 3042a4542e5SSrinivas Kandagatla 30584400305SSrinivas Kandagatla /* default read/write permissions */ 30684400305SSrinivas Kandagatla static struct bin_attribute bin_attr_rw_nvmem = { 30784400305SSrinivas Kandagatla .attr = { 30884400305SSrinivas Kandagatla .name = "nvmem", 30984400305SSrinivas Kandagatla .mode = 0644, 31084400305SSrinivas Kandagatla }, 31184400305SSrinivas Kandagatla .read = bin_attr_nvmem_read, 31284400305SSrinivas Kandagatla .write = bin_attr_nvmem_write, 31384400305SSrinivas Kandagatla }; 31484400305SSrinivas Kandagatla 31584400305SSrinivas Kandagatla static struct bin_attribute *nvmem_bin_attributes[] = { 31684400305SSrinivas Kandagatla &bin_attr_rw_nvmem, 31784400305SSrinivas Kandagatla NULL, 31884400305SSrinivas Kandagatla }; 31984400305SSrinivas Kandagatla 32084400305SSrinivas Kandagatla static const struct attribute_group nvmem_bin_group = { 32184400305SSrinivas Kandagatla .bin_attrs = nvmem_bin_attributes, 32284400305SSrinivas Kandagatla .attrs = nvmem_attrs, 32384400305SSrinivas Kandagatla .is_bin_visible = nvmem_bin_attr_is_visible, 32484400305SSrinivas Kandagatla }; 32584400305SSrinivas Kandagatla 32684400305SSrinivas Kandagatla static const struct attribute_group *nvmem_dev_groups[] = { 32784400305SSrinivas Kandagatla &nvmem_bin_group, 32884400305SSrinivas Kandagatla NULL, 32984400305SSrinivas Kandagatla }; 33084400305SSrinivas Kandagatla 3312a4542e5SSrinivas Kandagatla static struct bin_attribute bin_attr_nvmem_eeprom_compat = { 33284400305SSrinivas Kandagatla .attr = { 3332a4542e5SSrinivas Kandagatla .name = "eeprom", 33484400305SSrinivas Kandagatla }, 33584400305SSrinivas Kandagatla .read = bin_attr_nvmem_read, 33684400305SSrinivas Kandagatla .write = bin_attr_nvmem_write, 33784400305SSrinivas Kandagatla }; 33884400305SSrinivas Kandagatla 33984400305SSrinivas Kandagatla /* 34084400305SSrinivas Kandagatla * nvmem_setup_compat() - Create an additional binary entry in 34184400305SSrinivas Kandagatla * drivers sys directory, to be backwards compatible with the older 34284400305SSrinivas Kandagatla * drivers/misc/eeprom drivers. 34384400305SSrinivas Kandagatla */ 34484400305SSrinivas Kandagatla static int nvmem_sysfs_setup_compat(struct nvmem_device *nvmem, 34584400305SSrinivas Kandagatla const struct nvmem_config *config) 34684400305SSrinivas Kandagatla { 34784400305SSrinivas Kandagatla int rval; 34884400305SSrinivas Kandagatla 34984400305SSrinivas Kandagatla if (!config->compat) 35084400305SSrinivas Kandagatla return 0; 35184400305SSrinivas Kandagatla 35284400305SSrinivas Kandagatla if (!config->base_dev) 35384400305SSrinivas Kandagatla return -EINVAL; 35484400305SSrinivas Kandagatla 355fd307a4aSJiri Prchal if (config->type == NVMEM_TYPE_FRAM) 356fd307a4aSJiri Prchal bin_attr_nvmem_eeprom_compat.attr.name = "fram"; 357fd307a4aSJiri Prchal 3582a4542e5SSrinivas Kandagatla nvmem->eeprom = bin_attr_nvmem_eeprom_compat; 3592a4542e5SSrinivas Kandagatla nvmem->eeprom.attr.mode = nvmem_bin_attr_get_umode(nvmem); 36084400305SSrinivas Kandagatla nvmem->eeprom.size = nvmem->size; 36184400305SSrinivas Kandagatla #ifdef CONFIG_DEBUG_LOCK_ALLOC 36284400305SSrinivas Kandagatla nvmem->eeprom.attr.key = &eeprom_lock_key; 36384400305SSrinivas Kandagatla #endif 36484400305SSrinivas Kandagatla nvmem->eeprom.private = &nvmem->dev; 36584400305SSrinivas Kandagatla nvmem->base_dev = config->base_dev; 36684400305SSrinivas Kandagatla 36784400305SSrinivas Kandagatla rval = device_create_bin_file(nvmem->base_dev, &nvmem->eeprom); 36884400305SSrinivas Kandagatla if (rval) { 36984400305SSrinivas Kandagatla dev_err(&nvmem->dev, 37084400305SSrinivas Kandagatla "Failed to create eeprom binary file %d\n", rval); 37184400305SSrinivas Kandagatla return rval; 37284400305SSrinivas Kandagatla } 37384400305SSrinivas Kandagatla 37484400305SSrinivas Kandagatla nvmem->flags |= FLAG_COMPAT; 37584400305SSrinivas Kandagatla 37684400305SSrinivas Kandagatla return 0; 37784400305SSrinivas Kandagatla } 37884400305SSrinivas Kandagatla 37984400305SSrinivas Kandagatla static void nvmem_sysfs_remove_compat(struct nvmem_device *nvmem, 38084400305SSrinivas Kandagatla const struct nvmem_config *config) 38184400305SSrinivas Kandagatla { 38284400305SSrinivas Kandagatla if (config->compat) 38384400305SSrinivas Kandagatla device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); 38484400305SSrinivas Kandagatla } 38584400305SSrinivas Kandagatla 38684400305SSrinivas Kandagatla #else /* CONFIG_NVMEM_SYSFS */ 38784400305SSrinivas Kandagatla 38884400305SSrinivas Kandagatla static int nvmem_sysfs_setup_compat(struct nvmem_device *nvmem, 38984400305SSrinivas Kandagatla const struct nvmem_config *config) 39084400305SSrinivas Kandagatla { 39184400305SSrinivas Kandagatla return -ENOSYS; 39284400305SSrinivas Kandagatla } 39384400305SSrinivas Kandagatla static void nvmem_sysfs_remove_compat(struct nvmem_device *nvmem, 39484400305SSrinivas Kandagatla const struct nvmem_config *config) 39584400305SSrinivas Kandagatla { 39684400305SSrinivas Kandagatla } 39784400305SSrinivas Kandagatla 39884400305SSrinivas Kandagatla #endif /* CONFIG_NVMEM_SYSFS */ 399a8b44d5dSAndy Shevchenko 400eace75cfSSrinivas Kandagatla static void nvmem_release(struct device *dev) 401eace75cfSSrinivas Kandagatla { 402eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem = to_nvmem_device(dev); 403eace75cfSSrinivas Kandagatla 4041eb51d6aSBartosz Golaszewski ida_free(&nvmem_ida, nvmem->id); 405a9c3766cSKhouloud Touil gpiod_put(nvmem->wp_gpio); 406eace75cfSSrinivas Kandagatla kfree(nvmem); 407eace75cfSSrinivas Kandagatla } 408eace75cfSSrinivas Kandagatla 409eace75cfSSrinivas Kandagatla static const struct device_type nvmem_provider_type = { 410eace75cfSSrinivas Kandagatla .release = nvmem_release, 411eace75cfSSrinivas Kandagatla }; 412eace75cfSSrinivas Kandagatla 413eace75cfSSrinivas Kandagatla static struct bus_type nvmem_bus_type = { 414eace75cfSSrinivas Kandagatla .name = "nvmem", 415eace75cfSSrinivas Kandagatla }; 416eace75cfSSrinivas Kandagatla 4177ae6478bSSrinivas Kandagatla static void nvmem_cell_entry_drop(struct nvmem_cell_entry *cell) 418eace75cfSSrinivas Kandagatla { 419bee1138bSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_REMOVE, cell); 420c7235ee3SBartosz Golaszewski mutex_lock(&nvmem_mutex); 421eace75cfSSrinivas Kandagatla list_del(&cell->node); 422c7235ee3SBartosz Golaszewski mutex_unlock(&nvmem_mutex); 4230749aa25SSrinivas Kandagatla of_node_put(cell->np); 42416bb7abcSBitan Biswas kfree_const(cell->name); 425eace75cfSSrinivas Kandagatla kfree(cell); 426eace75cfSSrinivas Kandagatla } 427eace75cfSSrinivas Kandagatla 428eace75cfSSrinivas Kandagatla static void nvmem_device_remove_all_cells(const struct nvmem_device *nvmem) 429eace75cfSSrinivas Kandagatla { 4307ae6478bSSrinivas Kandagatla struct nvmem_cell_entry *cell, *p; 431eace75cfSSrinivas Kandagatla 432c7235ee3SBartosz Golaszewski list_for_each_entry_safe(cell, p, &nvmem->cells, node) 4337ae6478bSSrinivas Kandagatla nvmem_cell_entry_drop(cell); 434eace75cfSSrinivas Kandagatla } 435eace75cfSSrinivas Kandagatla 4367ae6478bSSrinivas Kandagatla static void nvmem_cell_entry_add(struct nvmem_cell_entry *cell) 437eace75cfSSrinivas Kandagatla { 438c7235ee3SBartosz Golaszewski mutex_lock(&nvmem_mutex); 439c7235ee3SBartosz Golaszewski list_add_tail(&cell->node, &cell->nvmem->cells); 440c7235ee3SBartosz Golaszewski mutex_unlock(&nvmem_mutex); 441bee1138bSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_ADD, cell); 442eace75cfSSrinivas Kandagatla } 443eace75cfSSrinivas Kandagatla 4447ae6478bSSrinivas Kandagatla static int nvmem_cell_info_to_nvmem_cell_entry_nodup(struct nvmem_device *nvmem, 445eace75cfSSrinivas Kandagatla const struct nvmem_cell_info *info, 4467ae6478bSSrinivas Kandagatla struct nvmem_cell_entry *cell) 447eace75cfSSrinivas Kandagatla { 448eace75cfSSrinivas Kandagatla cell->nvmem = nvmem; 449eace75cfSSrinivas Kandagatla cell->offset = info->offset; 45055d4980cSRafał Miłecki cell->raw_len = info->raw_len ?: info->bytes; 451eace75cfSSrinivas Kandagatla cell->bytes = info->bytes; 452fc9eec4dSVadym Kochan cell->name = info->name; 453345ec382SMichael Walle cell->read_post_process = info->read_post_process; 4548a134fd9SMichael Walle cell->priv = info->priv; 455eace75cfSSrinivas Kandagatla 456eace75cfSSrinivas Kandagatla cell->bit_offset = info->bit_offset; 457eace75cfSSrinivas Kandagatla cell->nbits = info->nbits; 458dbc2f620SRafał Miłecki cell->np = info->np; 459eace75cfSSrinivas Kandagatla 460eace75cfSSrinivas Kandagatla if (cell->nbits) 461eace75cfSSrinivas Kandagatla cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset, 462eace75cfSSrinivas Kandagatla BITS_PER_BYTE); 463eace75cfSSrinivas Kandagatla 464eace75cfSSrinivas Kandagatla if (!IS_ALIGNED(cell->offset, nvmem->stride)) { 465eace75cfSSrinivas Kandagatla dev_err(&nvmem->dev, 466eace75cfSSrinivas Kandagatla "cell %s unaligned to nvmem stride %d\n", 467fc9eec4dSVadym Kochan cell->name ?: "<unknown>", nvmem->stride); 468eace75cfSSrinivas Kandagatla return -EINVAL; 469eace75cfSSrinivas Kandagatla } 470eace75cfSSrinivas Kandagatla 471eace75cfSSrinivas Kandagatla return 0; 472eace75cfSSrinivas Kandagatla } 473eace75cfSSrinivas Kandagatla 4747ae6478bSSrinivas Kandagatla static int nvmem_cell_info_to_nvmem_cell_entry(struct nvmem_device *nvmem, 475fc9eec4dSVadym Kochan const struct nvmem_cell_info *info, 4767ae6478bSSrinivas Kandagatla struct nvmem_cell_entry *cell) 477fc9eec4dSVadym Kochan { 478fc9eec4dSVadym Kochan int err; 479fc9eec4dSVadym Kochan 4807ae6478bSSrinivas Kandagatla err = nvmem_cell_info_to_nvmem_cell_entry_nodup(nvmem, info, cell); 481fc9eec4dSVadym Kochan if (err) 482fc9eec4dSVadym Kochan return err; 483fc9eec4dSVadym Kochan 484fc9eec4dSVadym Kochan cell->name = kstrdup_const(info->name, GFP_KERNEL); 485fc9eec4dSVadym Kochan if (!cell->name) 486fc9eec4dSVadym Kochan return -ENOMEM; 487fc9eec4dSVadym Kochan 488fc9eec4dSVadym Kochan return 0; 489fc9eec4dSVadym Kochan } 490fc9eec4dSVadym Kochan 491b3db17e4SAndrew Lunn /** 4922ded6830SMichael Walle * nvmem_add_one_cell() - Add one cell information to an nvmem device 4932ded6830SMichael Walle * 4942ded6830SMichael Walle * @nvmem: nvmem device to add cells to. 4952ded6830SMichael Walle * @info: nvmem cell info to add to the device 4962ded6830SMichael Walle * 4972ded6830SMichael Walle * Return: 0 or negative error code on failure. 4982ded6830SMichael Walle */ 4992ded6830SMichael Walle int nvmem_add_one_cell(struct nvmem_device *nvmem, 5002ded6830SMichael Walle const struct nvmem_cell_info *info) 5012ded6830SMichael Walle { 5022ded6830SMichael Walle struct nvmem_cell_entry *cell; 5032ded6830SMichael Walle int rval; 5042ded6830SMichael Walle 5052ded6830SMichael Walle cell = kzalloc(sizeof(*cell), GFP_KERNEL); 5062ded6830SMichael Walle if (!cell) 5072ded6830SMichael Walle return -ENOMEM; 5082ded6830SMichael Walle 5092ded6830SMichael Walle rval = nvmem_cell_info_to_nvmem_cell_entry(nvmem, info, cell); 5102ded6830SMichael Walle if (rval) { 5112ded6830SMichael Walle kfree(cell); 5122ded6830SMichael Walle return rval; 5132ded6830SMichael Walle } 5142ded6830SMichael Walle 5152ded6830SMichael Walle nvmem_cell_entry_add(cell); 5162ded6830SMichael Walle 5172ded6830SMichael Walle return 0; 5182ded6830SMichael Walle } 5192ded6830SMichael Walle EXPORT_SYMBOL_GPL(nvmem_add_one_cell); 5202ded6830SMichael Walle 5212ded6830SMichael Walle /** 522b3db17e4SAndrew Lunn * nvmem_add_cells() - Add cell information to an nvmem device 523b3db17e4SAndrew Lunn * 524b3db17e4SAndrew Lunn * @nvmem: nvmem device to add cells to. 525b3db17e4SAndrew Lunn * @info: nvmem cell info to add to the device 526b3db17e4SAndrew Lunn * @ncells: number of cells in info 527b3db17e4SAndrew Lunn * 528b3db17e4SAndrew Lunn * Return: 0 or negative error code on failure. 529b3db17e4SAndrew Lunn */ 530ef92ab30SSrinivas Kandagatla static int nvmem_add_cells(struct nvmem_device *nvmem, 531b3db17e4SAndrew Lunn const struct nvmem_cell_info *info, 532b3db17e4SAndrew Lunn int ncells) 533eace75cfSSrinivas Kandagatla { 5342ded6830SMichael Walle int i, rval; 535eace75cfSSrinivas Kandagatla 536b3db17e4SAndrew Lunn for (i = 0; i < ncells; i++) { 5372ded6830SMichael Walle rval = nvmem_add_one_cell(nvmem, &info[i]); 5382ded6830SMichael Walle if (rval) 539eace75cfSSrinivas Kandagatla return rval; 540eace75cfSSrinivas Kandagatla } 541eace75cfSSrinivas Kandagatla 5422ded6830SMichael Walle return 0; 5432ded6830SMichael Walle } 5442ded6830SMichael Walle 545bee1138bSBartosz Golaszewski /** 546bee1138bSBartosz Golaszewski * nvmem_register_notifier() - Register a notifier block for nvmem events. 547bee1138bSBartosz Golaszewski * 548bee1138bSBartosz Golaszewski * @nb: notifier block to be called on nvmem events. 549bee1138bSBartosz Golaszewski * 550bee1138bSBartosz Golaszewski * Return: 0 on success, negative error number on failure. 551bee1138bSBartosz Golaszewski */ 552bee1138bSBartosz Golaszewski int nvmem_register_notifier(struct notifier_block *nb) 553bee1138bSBartosz Golaszewski { 554bee1138bSBartosz Golaszewski return blocking_notifier_chain_register(&nvmem_notifier, nb); 555bee1138bSBartosz Golaszewski } 556bee1138bSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_register_notifier); 557bee1138bSBartosz Golaszewski 558bee1138bSBartosz Golaszewski /** 559bee1138bSBartosz Golaszewski * nvmem_unregister_notifier() - Unregister a notifier block for nvmem events. 560bee1138bSBartosz Golaszewski * 561bee1138bSBartosz Golaszewski * @nb: notifier block to be unregistered. 562bee1138bSBartosz Golaszewski * 563bee1138bSBartosz Golaszewski * Return: 0 on success, negative error number on failure. 564bee1138bSBartosz Golaszewski */ 565bee1138bSBartosz Golaszewski int nvmem_unregister_notifier(struct notifier_block *nb) 566bee1138bSBartosz Golaszewski { 567bee1138bSBartosz Golaszewski return blocking_notifier_chain_unregister(&nvmem_notifier, nb); 568bee1138bSBartosz Golaszewski } 569bee1138bSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_unregister_notifier); 570bee1138bSBartosz Golaszewski 571b985f4cbSBartosz Golaszewski static int nvmem_add_cells_from_table(struct nvmem_device *nvmem) 572b985f4cbSBartosz Golaszewski { 573b985f4cbSBartosz Golaszewski const struct nvmem_cell_info *info; 574b985f4cbSBartosz Golaszewski struct nvmem_cell_table *table; 5757ae6478bSSrinivas Kandagatla struct nvmem_cell_entry *cell; 576b985f4cbSBartosz Golaszewski int rval = 0, i; 577b985f4cbSBartosz Golaszewski 578b985f4cbSBartosz Golaszewski mutex_lock(&nvmem_cell_mutex); 579b985f4cbSBartosz Golaszewski list_for_each_entry(table, &nvmem_cell_tables, node) { 580b985f4cbSBartosz Golaszewski if (strcmp(nvmem_dev_name(nvmem), table->nvmem_name) == 0) { 581b985f4cbSBartosz Golaszewski for (i = 0; i < table->ncells; i++) { 582b985f4cbSBartosz Golaszewski info = &table->cells[i]; 583b985f4cbSBartosz Golaszewski 584b985f4cbSBartosz Golaszewski cell = kzalloc(sizeof(*cell), GFP_KERNEL); 585b985f4cbSBartosz Golaszewski if (!cell) { 586b985f4cbSBartosz Golaszewski rval = -ENOMEM; 587b985f4cbSBartosz Golaszewski goto out; 588b985f4cbSBartosz Golaszewski } 589b985f4cbSBartosz Golaszewski 5907ae6478bSSrinivas Kandagatla rval = nvmem_cell_info_to_nvmem_cell_entry(nvmem, info, cell); 591b985f4cbSBartosz Golaszewski if (rval) { 592b985f4cbSBartosz Golaszewski kfree(cell); 593b985f4cbSBartosz Golaszewski goto out; 594b985f4cbSBartosz Golaszewski } 595b985f4cbSBartosz Golaszewski 5967ae6478bSSrinivas Kandagatla nvmem_cell_entry_add(cell); 597b985f4cbSBartosz Golaszewski } 598b985f4cbSBartosz Golaszewski } 599b985f4cbSBartosz Golaszewski } 600b985f4cbSBartosz Golaszewski 601b985f4cbSBartosz Golaszewski out: 602b985f4cbSBartosz Golaszewski mutex_unlock(&nvmem_cell_mutex); 603b985f4cbSBartosz Golaszewski return rval; 604b985f4cbSBartosz Golaszewski } 605b985f4cbSBartosz Golaszewski 6067ae6478bSSrinivas Kandagatla static struct nvmem_cell_entry * 6077ae6478bSSrinivas Kandagatla nvmem_find_cell_entry_by_name(struct nvmem_device *nvmem, const char *cell_id) 608506157beSBartosz Golaszewski { 6097ae6478bSSrinivas Kandagatla struct nvmem_cell_entry *iter, *cell = NULL; 610506157beSBartosz Golaszewski 611506157beSBartosz Golaszewski mutex_lock(&nvmem_mutex); 6121c832674SAlban Bedel list_for_each_entry(iter, &nvmem->cells, node) { 6131c832674SAlban Bedel if (strcmp(cell_id, iter->name) == 0) { 6141c832674SAlban Bedel cell = iter; 615506157beSBartosz Golaszewski break; 616506157beSBartosz Golaszewski } 6171c832674SAlban Bedel } 618506157beSBartosz Golaszewski mutex_unlock(&nvmem_mutex); 619506157beSBartosz Golaszewski 620506157beSBartosz Golaszewski return cell; 621506157beSBartosz Golaszewski } 622506157beSBartosz Golaszewski 623fd3bb8f5SEvan Green static int nvmem_validate_keepouts(struct nvmem_device *nvmem) 624fd3bb8f5SEvan Green { 625fd3bb8f5SEvan Green unsigned int cur = 0; 626fd3bb8f5SEvan Green const struct nvmem_keepout *keepout = nvmem->keepout; 627fd3bb8f5SEvan Green const struct nvmem_keepout *keepoutend = keepout + nvmem->nkeepout; 628fd3bb8f5SEvan Green 629fd3bb8f5SEvan Green while (keepout < keepoutend) { 630fd3bb8f5SEvan Green /* Ensure keepouts are sorted and don't overlap. */ 631fd3bb8f5SEvan Green if (keepout->start < cur) { 632fd3bb8f5SEvan Green dev_err(&nvmem->dev, 633fd3bb8f5SEvan Green "Keepout regions aren't sorted or overlap.\n"); 634fd3bb8f5SEvan Green 635fd3bb8f5SEvan Green return -ERANGE; 636fd3bb8f5SEvan Green } 637fd3bb8f5SEvan Green 638fd3bb8f5SEvan Green if (keepout->end < keepout->start) { 639fd3bb8f5SEvan Green dev_err(&nvmem->dev, 640fd3bb8f5SEvan Green "Invalid keepout region.\n"); 641fd3bb8f5SEvan Green 642fd3bb8f5SEvan Green return -EINVAL; 643fd3bb8f5SEvan Green } 644fd3bb8f5SEvan Green 645fd3bb8f5SEvan Green /* 646fd3bb8f5SEvan Green * Validate keepouts (and holes between) don't violate 647fd3bb8f5SEvan Green * word_size constraints. 648fd3bb8f5SEvan Green */ 649fd3bb8f5SEvan Green if ((keepout->end - keepout->start < nvmem->word_size) || 650fd3bb8f5SEvan Green ((keepout->start != cur) && 651fd3bb8f5SEvan Green (keepout->start - cur < nvmem->word_size))) { 652fd3bb8f5SEvan Green 653fd3bb8f5SEvan Green dev_err(&nvmem->dev, 654fd3bb8f5SEvan Green "Keepout regions violate word_size constraints.\n"); 655fd3bb8f5SEvan Green 656fd3bb8f5SEvan Green return -ERANGE; 657fd3bb8f5SEvan Green } 658fd3bb8f5SEvan Green 659fd3bb8f5SEvan Green /* Validate keepouts don't violate stride (alignment). */ 660fd3bb8f5SEvan Green if (!IS_ALIGNED(keepout->start, nvmem->stride) || 661fd3bb8f5SEvan Green !IS_ALIGNED(keepout->end, nvmem->stride)) { 662fd3bb8f5SEvan Green 663fd3bb8f5SEvan Green dev_err(&nvmem->dev, 664fd3bb8f5SEvan Green "Keepout regions violate stride.\n"); 665fd3bb8f5SEvan Green 666fd3bb8f5SEvan Green return -EINVAL; 667fd3bb8f5SEvan Green } 668fd3bb8f5SEvan Green 669fd3bb8f5SEvan Green cur = keepout->end; 670fd3bb8f5SEvan Green keepout++; 671fd3bb8f5SEvan Green } 672fd3bb8f5SEvan Green 673fd3bb8f5SEvan Green return 0; 674fd3bb8f5SEvan Green } 675fd3bb8f5SEvan Green 67627f699e5SRafał Miłecki static int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_node *np) 677e888d445SBartosz Golaszewski { 678de12c969SMichael Walle struct nvmem_layout *layout = nvmem->layout; 679e888d445SBartosz Golaszewski struct device *dev = &nvmem->dev; 68050014d65SMichael Walle struct device_node *child; 681e888d445SBartosz Golaszewski const __be32 *addr; 68250014d65SMichael Walle int len, ret; 683e888d445SBartosz Golaszewski 68427f699e5SRafał Miłecki for_each_child_of_node(np, child) { 68550014d65SMichael Walle struct nvmem_cell_info info = {0}; 686e888d445SBartosz Golaszewski 687e888d445SBartosz Golaszewski addr = of_get_property(child, "reg", &len); 6880445efacSAhmad Fatoum if (!addr) 6890445efacSAhmad Fatoum continue; 6900445efacSAhmad Fatoum if (len < 2 * sizeof(u32)) { 691e888d445SBartosz Golaszewski dev_err(dev, "nvmem: invalid reg on %pOF\n", child); 69263879e29SChristophe JAILLET of_node_put(child); 693e888d445SBartosz Golaszewski return -EINVAL; 694e888d445SBartosz Golaszewski } 695e888d445SBartosz Golaszewski 69650014d65SMichael Walle info.offset = be32_to_cpup(addr++); 69750014d65SMichael Walle info.bytes = be32_to_cpup(addr); 69850014d65SMichael Walle info.name = kasprintf(GFP_KERNEL, "%pOFn", child); 699e888d445SBartosz Golaszewski 700e888d445SBartosz Golaszewski addr = of_get_property(child, "bits", &len); 701e888d445SBartosz Golaszewski if (addr && len == (2 * sizeof(u32))) { 70250014d65SMichael Walle info.bit_offset = be32_to_cpup(addr++); 70350014d65SMichael Walle info.nbits = be32_to_cpup(addr); 704e888d445SBartosz Golaszewski } 705e888d445SBartosz Golaszewski 70650014d65SMichael Walle info.np = of_node_get(child); 707e888d445SBartosz Golaszewski 708de12c969SMichael Walle if (layout && layout->fixup_cell_info) 709de12c969SMichael Walle layout->fixup_cell_info(nvmem, layout, &info); 710de12c969SMichael Walle 71150014d65SMichael Walle ret = nvmem_add_one_cell(nvmem, &info); 71250014d65SMichael Walle kfree(info.name); 71350014d65SMichael Walle if (ret) { 71463879e29SChristophe JAILLET of_node_put(child); 71550014d65SMichael Walle return ret; 716e888d445SBartosz Golaszewski } 717e888d445SBartosz Golaszewski } 718e888d445SBartosz Golaszewski 719e888d445SBartosz Golaszewski return 0; 720e888d445SBartosz Golaszewski } 721e888d445SBartosz Golaszewski 72227f699e5SRafał Miłecki static int nvmem_add_cells_from_legacy_of(struct nvmem_device *nvmem) 72327f699e5SRafał Miłecki { 72427f699e5SRafał Miłecki return nvmem_add_cells_from_dt(nvmem, nvmem->dev.of_node); 72527f699e5SRafał Miłecki } 72627f699e5SRafał Miłecki 72727f699e5SRafał Miłecki static int nvmem_add_cells_from_fixed_layout(struct nvmem_device *nvmem) 72827f699e5SRafał Miłecki { 72927f699e5SRafał Miłecki struct device_node *layout_np; 73027f699e5SRafał Miłecki int err = 0; 73127f699e5SRafał Miłecki 73227f699e5SRafał Miłecki layout_np = of_nvmem_layout_get_container(nvmem); 73327f699e5SRafał Miłecki if (!layout_np) 73427f699e5SRafał Miłecki return 0; 73527f699e5SRafał Miłecki 73627f699e5SRafał Miłecki if (of_device_is_compatible(layout_np, "fixed-layout")) 73727f699e5SRafał Miłecki err = nvmem_add_cells_from_dt(nvmem, layout_np); 73827f699e5SRafał Miłecki 73927f699e5SRafał Miłecki of_node_put(layout_np); 74027f699e5SRafał Miłecki 74127f699e5SRafał Miłecki return err; 74227f699e5SRafał Miłecki } 74327f699e5SRafał Miłecki 744266570f4SMichael Walle int __nvmem_layout_register(struct nvmem_layout *layout, struct module *owner) 745266570f4SMichael Walle { 746266570f4SMichael Walle layout->owner = owner; 747266570f4SMichael Walle 748266570f4SMichael Walle spin_lock(&nvmem_layout_lock); 749266570f4SMichael Walle list_add(&layout->node, &nvmem_layouts); 750266570f4SMichael Walle spin_unlock(&nvmem_layout_lock); 751266570f4SMichael Walle 752eb176cb4SMiquel Raynal blocking_notifier_call_chain(&nvmem_notifier, NVMEM_LAYOUT_ADD, layout); 753eb176cb4SMiquel Raynal 754266570f4SMichael Walle return 0; 755266570f4SMichael Walle } 756266570f4SMichael Walle EXPORT_SYMBOL_GPL(__nvmem_layout_register); 757266570f4SMichael Walle 758266570f4SMichael Walle void nvmem_layout_unregister(struct nvmem_layout *layout) 759266570f4SMichael Walle { 760eb176cb4SMiquel Raynal blocking_notifier_call_chain(&nvmem_notifier, NVMEM_LAYOUT_REMOVE, layout); 761eb176cb4SMiquel Raynal 762266570f4SMichael Walle spin_lock(&nvmem_layout_lock); 763266570f4SMichael Walle list_del(&layout->node); 764266570f4SMichael Walle spin_unlock(&nvmem_layout_lock); 765266570f4SMichael Walle } 766266570f4SMichael Walle EXPORT_SYMBOL_GPL(nvmem_layout_unregister); 767266570f4SMichael Walle 768266570f4SMichael Walle static struct nvmem_layout *nvmem_layout_get(struct nvmem_device *nvmem) 769266570f4SMichael Walle { 770b9740091SMiquel Raynal struct device_node *layout_np; 7716468a6f4SMiquel Raynal struct nvmem_layout *l, *layout = ERR_PTR(-EPROBE_DEFER); 772266570f4SMichael Walle 773b9740091SMiquel Raynal layout_np = of_nvmem_layout_get_container(nvmem); 774266570f4SMichael Walle if (!layout_np) 775266570f4SMichael Walle return NULL; 776266570f4SMichael Walle 777b7c1e537SMiquel Raynal /* Fixed layouts don't have a matching driver */ 778b7c1e537SMiquel Raynal if (of_device_is_compatible(layout_np, "fixed-layout")) { 779b7c1e537SMiquel Raynal of_node_put(layout_np); 780b7c1e537SMiquel Raynal return NULL; 781b7c1e537SMiquel Raynal } 782b7c1e537SMiquel Raynal 783b1c37becSMiquel Raynal /* 784b1c37becSMiquel Raynal * In case the nvmem device was built-in while the layout was built as a 785b1c37becSMiquel Raynal * module, we shall manually request the layout driver loading otherwise 786b1c37becSMiquel Raynal * we'll never have any match. 787b1c37becSMiquel Raynal */ 788b1c37becSMiquel Raynal of_request_module(layout_np); 789b1c37becSMiquel Raynal 790266570f4SMichael Walle spin_lock(&nvmem_layout_lock); 791266570f4SMichael Walle 792266570f4SMichael Walle list_for_each_entry(l, &nvmem_layouts, node) { 793266570f4SMichael Walle if (of_match_node(l->of_match_table, layout_np)) { 794266570f4SMichael Walle if (try_module_get(l->owner)) 795266570f4SMichael Walle layout = l; 796266570f4SMichael Walle 797266570f4SMichael Walle break; 798266570f4SMichael Walle } 799266570f4SMichael Walle } 800266570f4SMichael Walle 801266570f4SMichael Walle spin_unlock(&nvmem_layout_lock); 802266570f4SMichael Walle of_node_put(layout_np); 803266570f4SMichael Walle 804266570f4SMichael Walle return layout; 805266570f4SMichael Walle } 806266570f4SMichael Walle 807266570f4SMichael Walle static void nvmem_layout_put(struct nvmem_layout *layout) 808266570f4SMichael Walle { 809266570f4SMichael Walle if (layout) 810266570f4SMichael Walle module_put(layout->owner); 811266570f4SMichael Walle } 812266570f4SMichael Walle 813266570f4SMichael Walle static int nvmem_add_cells_from_layout(struct nvmem_device *nvmem) 814266570f4SMichael Walle { 815266570f4SMichael Walle struct nvmem_layout *layout = nvmem->layout; 816266570f4SMichael Walle int ret; 817266570f4SMichael Walle 818266570f4SMichael Walle if (layout && layout->add_cells) { 819266570f4SMichael Walle ret = layout->add_cells(&nvmem->dev, nvmem, layout); 820266570f4SMichael Walle if (ret) 821266570f4SMichael Walle return ret; 822266570f4SMichael Walle } 823266570f4SMichael Walle 824266570f4SMichael Walle return 0; 825266570f4SMichael Walle } 826266570f4SMichael Walle 827266570f4SMichael Walle #if IS_ENABLED(CONFIG_OF) 828266570f4SMichael Walle struct device_node *of_nvmem_layout_get_container(struct nvmem_device *nvmem) 829266570f4SMichael Walle { 830266570f4SMichael Walle return of_get_child_by_name(nvmem->dev.of_node, "nvmem-layout"); 831266570f4SMichael Walle } 832266570f4SMichael Walle EXPORT_SYMBOL_GPL(of_nvmem_layout_get_container); 833266570f4SMichael Walle #endif 834266570f4SMichael Walle 835266570f4SMichael Walle const void *nvmem_layout_get_match_data(struct nvmem_device *nvmem, 836266570f4SMichael Walle struct nvmem_layout *layout) 837266570f4SMichael Walle { 838266570f4SMichael Walle struct device_node __maybe_unused *layout_np; 839266570f4SMichael Walle const struct of_device_id *match; 840266570f4SMichael Walle 841266570f4SMichael Walle layout_np = of_nvmem_layout_get_container(nvmem); 842266570f4SMichael Walle match = of_match_node(layout->of_match_table, layout_np); 843266570f4SMichael Walle 844266570f4SMichael Walle return match ? match->data : NULL; 845266570f4SMichael Walle } 846266570f4SMichael Walle EXPORT_SYMBOL_GPL(nvmem_layout_get_match_data); 847266570f4SMichael Walle 848eace75cfSSrinivas Kandagatla /** 849eace75cfSSrinivas Kandagatla * nvmem_register() - Register a nvmem device for given nvmem_config. 8503a758071SAndreas Färber * Also creates a binary entry in /sys/bus/nvmem/devices/dev-name/nvmem 851eace75cfSSrinivas Kandagatla * 852eace75cfSSrinivas Kandagatla * @config: nvmem device configuration with which nvmem device is created. 853eace75cfSSrinivas Kandagatla * 854eace75cfSSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device 855eace75cfSSrinivas Kandagatla * on success. 856eace75cfSSrinivas Kandagatla */ 857eace75cfSSrinivas Kandagatla 858eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem_register(const struct nvmem_config *config) 859eace75cfSSrinivas Kandagatla { 860eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem; 861eace75cfSSrinivas Kandagatla int rval; 862eace75cfSSrinivas Kandagatla 863eace75cfSSrinivas Kandagatla if (!config->dev) 864eace75cfSSrinivas Kandagatla return ERR_PTR(-EINVAL); 865eace75cfSSrinivas Kandagatla 866061a320bSSrinivas Kandagatla if (!config->reg_read && !config->reg_write) 867061a320bSSrinivas Kandagatla return ERR_PTR(-EINVAL); 868061a320bSSrinivas Kandagatla 869eace75cfSSrinivas Kandagatla nvmem = kzalloc(sizeof(*nvmem), GFP_KERNEL); 870eace75cfSSrinivas Kandagatla if (!nvmem) 871eace75cfSSrinivas Kandagatla return ERR_PTR(-ENOMEM); 872eace75cfSSrinivas Kandagatla 8731eb51d6aSBartosz Golaszewski rval = ida_alloc(&nvmem_ida, GFP_KERNEL); 874eace75cfSSrinivas Kandagatla if (rval < 0) { 875eace75cfSSrinivas Kandagatla kfree(nvmem); 876eace75cfSSrinivas Kandagatla return ERR_PTR(rval); 877eace75cfSSrinivas Kandagatla } 87831c6ff51SBartosz Golaszewski 8793bd747c7SRussell King (Oracle) nvmem->id = rval; 8803bd747c7SRussell King (Oracle) 881560181d3SRussell King (Oracle) nvmem->dev.type = &nvmem_provider_type; 882560181d3SRussell King (Oracle) nvmem->dev.bus = &nvmem_bus_type; 883560181d3SRussell King (Oracle) nvmem->dev.parent = config->dev; 884560181d3SRussell King (Oracle) 885560181d3SRussell King (Oracle) device_initialize(&nvmem->dev); 886560181d3SRussell King (Oracle) 887569653f0SRussell King (Oracle) if (!config->ignore_wp) 8882a127da4SKhouloud Touil nvmem->wp_gpio = gpiod_get_optional(config->dev, "wp", 8892a127da4SKhouloud Touil GPIOD_OUT_HIGH); 890f7d8d7dcSBartosz Golaszewski if (IS_ERR(nvmem->wp_gpio)) { 891f7d8d7dcSBartosz Golaszewski rval = PTR_ERR(nvmem->wp_gpio); 8920c4862b1SRussell King (Oracle) nvmem->wp_gpio = NULL; 893560181d3SRussell King (Oracle) goto err_put_device; 894f7d8d7dcSBartosz Golaszewski } 8952a127da4SKhouloud Touil 896c1de7f43SBartosz Golaszewski kref_init(&nvmem->refcnt); 897c7235ee3SBartosz Golaszewski INIT_LIST_HEAD(&nvmem->cells); 898c1de7f43SBartosz Golaszewski 899eace75cfSSrinivas Kandagatla nvmem->owner = config->owner; 90017eb18d6SMasahiro Yamada if (!nvmem->owner && config->dev->driver) 90117eb18d6SMasahiro Yamada nvmem->owner = config->dev->driver->owner; 90299897efdSHeiner Kallweit nvmem->stride = config->stride ?: 1; 90399897efdSHeiner Kallweit nvmem->word_size = config->word_size ?: 1; 904795ddd18SSrinivas Kandagatla nvmem->size = config->size; 905e6de179dSSrinivas Kandagatla nvmem->root_only = config->root_only; 906795ddd18SSrinivas Kandagatla nvmem->priv = config->priv; 90716688453SAlexandre Belloni nvmem->type = config->type; 908795ddd18SSrinivas Kandagatla nvmem->reg_read = config->reg_read; 909795ddd18SSrinivas Kandagatla nvmem->reg_write = config->reg_write; 910fd3bb8f5SEvan Green nvmem->keepout = config->keepout; 911fd3bb8f5SEvan Green nvmem->nkeepout = config->nkeepout; 9121333a677SMichael Walle if (config->of_node) 9131333a677SMichael Walle nvmem->dev.of_node = config->of_node; 914f4cf4e5dSRafał Miłecki else 915fc2f9970SHeiner Kallweit nvmem->dev.of_node = config->dev->of_node; 916fd0f4906SAndrey Smirnov 917731aa3faSSrinivas Kandagatla switch (config->id) { 918731aa3faSSrinivas Kandagatla case NVMEM_DEVID_NONE: 9195544e90cSGaosheng Cui rval = dev_set_name(&nvmem->dev, "%s", config->name); 920731aa3faSSrinivas Kandagatla break; 921731aa3faSSrinivas Kandagatla case NVMEM_DEVID_AUTO: 9225544e90cSGaosheng Cui rval = dev_set_name(&nvmem->dev, "%s%d", config->name, nvmem->id); 923731aa3faSSrinivas Kandagatla break; 924731aa3faSSrinivas Kandagatla default: 9255544e90cSGaosheng Cui rval = dev_set_name(&nvmem->dev, "%s%d", 9265253193dSAban Bedel config->name ? : "nvmem", 9275253193dSAban Bedel config->name ? config->id : nvmem->id); 928731aa3faSSrinivas Kandagatla break; 929fd0f4906SAndrey Smirnov } 930eace75cfSSrinivas Kandagatla 931560181d3SRussell King (Oracle) if (rval) 932560181d3SRussell King (Oracle) goto err_put_device; 9335544e90cSGaosheng Cui 9341716cfe8SAlban Bedel nvmem->read_only = device_property_present(config->dev, "read-only") || 9351716cfe8SAlban Bedel config->read_only || !nvmem->reg_write; 936eace75cfSSrinivas Kandagatla 93784400305SSrinivas Kandagatla #ifdef CONFIG_NVMEM_SYSFS 93884400305SSrinivas Kandagatla nvmem->dev.groups = nvmem_dev_groups; 93984400305SSrinivas Kandagatla #endif 940eace75cfSSrinivas Kandagatla 941bd124456SGaosheng Cui if (nvmem->nkeepout) { 942bd124456SGaosheng Cui rval = nvmem_validate_keepouts(nvmem); 943bd124456SGaosheng Cui if (rval) 944ab3428cfSRussell King (Oracle) goto err_put_device; 945bd124456SGaosheng Cui } 946bd124456SGaosheng Cui 947b6c217abSAndrew Lunn if (config->compat) { 948ae0c2d72SSrinivas Kandagatla rval = nvmem_sysfs_setup_compat(nvmem, config); 949b6c217abSAndrew Lunn if (rval) 950ab3428cfSRussell King (Oracle) goto err_put_device; 951eace75cfSSrinivas Kandagatla } 952eace75cfSSrinivas Kandagatla 953266570f4SMichael Walle /* 954266570f4SMichael Walle * If the driver supplied a layout by config->layout, the module 955266570f4SMichael Walle * pointer will be NULL and nvmem_layout_put() will be a noop. 956266570f4SMichael Walle */ 957266570f4SMichael Walle nvmem->layout = config->layout ?: nvmem_layout_get(nvmem); 9586468a6f4SMiquel Raynal if (IS_ERR(nvmem->layout)) { 9596468a6f4SMiquel Raynal rval = PTR_ERR(nvmem->layout); 9606468a6f4SMiquel Raynal nvmem->layout = NULL; 9616468a6f4SMiquel Raynal 9626468a6f4SMiquel Raynal if (rval == -EPROBE_DEFER) 9636468a6f4SMiquel Raynal goto err_teardown_compat; 9646468a6f4SMiquel Raynal } 965266570f4SMichael Walle 966fa72d847SBartosz Golaszewski if (config->cells) { 967fa72d847SBartosz Golaszewski rval = nvmem_add_cells(nvmem, config->cells, config->ncells); 968fa72d847SBartosz Golaszewski if (rval) 969db3546d5SMichael Walle goto err_remove_cells; 970fa72d847SBartosz Golaszewski } 971eace75cfSSrinivas Kandagatla 972b985f4cbSBartosz Golaszewski rval = nvmem_add_cells_from_table(nvmem); 973b985f4cbSBartosz Golaszewski if (rval) 974b985f4cbSBartosz Golaszewski goto err_remove_cells; 975b985f4cbSBartosz Golaszewski 9762cc3b37fSRafał Miłecki if (config->add_legacy_fixed_of_cells) { 97727f699e5SRafał Miłecki rval = nvmem_add_cells_from_legacy_of(nvmem); 978e888d445SBartosz Golaszewski if (rval) 979e888d445SBartosz Golaszewski goto err_remove_cells; 9802cc3b37fSRafał Miłecki } 981e888d445SBartosz Golaszewski 98227f699e5SRafał Miłecki rval = nvmem_add_cells_from_fixed_layout(nvmem); 98327f699e5SRafał Miłecki if (rval) 98427f699e5SRafał Miłecki goto err_remove_cells; 98527f699e5SRafał Miłecki 986266570f4SMichael Walle rval = nvmem_add_cells_from_layout(nvmem); 987266570f4SMichael Walle if (rval) 988266570f4SMichael Walle goto err_remove_cells; 989266570f4SMichael Walle 990f4d1d17eSMiquel Raynal dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name); 991f4d1d17eSMiquel Raynal 992f4d1d17eSMiquel Raynal rval = device_add(&nvmem->dev); 993f4d1d17eSMiquel Raynal if (rval) 994f4d1d17eSMiquel Raynal goto err_remove_cells; 995f4d1d17eSMiquel Raynal 996f4853e1cSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_ADD, nvmem); 997bee1138bSBartosz Golaszewski 998eace75cfSSrinivas Kandagatla return nvmem; 9993360acdfSJohan Hovold 1000b985f4cbSBartosz Golaszewski err_remove_cells: 1001b985f4cbSBartosz Golaszewski nvmem_device_remove_all_cells(nvmem); 1002266570f4SMichael Walle nvmem_layout_put(nvmem->layout); 10036468a6f4SMiquel Raynal err_teardown_compat: 1004fa72d847SBartosz Golaszewski if (config->compat) 1005ae0c2d72SSrinivas Kandagatla nvmem_sysfs_remove_compat(nvmem, config); 10063360acdfSJohan Hovold err_put_device: 10073360acdfSJohan Hovold put_device(&nvmem->dev); 10083360acdfSJohan Hovold 1009b6c217abSAndrew Lunn return ERR_PTR(rval); 1010eace75cfSSrinivas Kandagatla } 1011eace75cfSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_register); 1012eace75cfSSrinivas Kandagatla 1013c1de7f43SBartosz Golaszewski static void nvmem_device_release(struct kref *kref) 1014c1de7f43SBartosz Golaszewski { 1015c1de7f43SBartosz Golaszewski struct nvmem_device *nvmem; 1016c1de7f43SBartosz Golaszewski 1017c1de7f43SBartosz Golaszewski nvmem = container_of(kref, struct nvmem_device, refcnt); 1018c1de7f43SBartosz Golaszewski 1019bee1138bSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_REMOVE, nvmem); 1020bee1138bSBartosz Golaszewski 1021c1de7f43SBartosz Golaszewski if (nvmem->flags & FLAG_COMPAT) 1022c1de7f43SBartosz Golaszewski device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); 1023c1de7f43SBartosz Golaszewski 1024c1de7f43SBartosz Golaszewski nvmem_device_remove_all_cells(nvmem); 1025266570f4SMichael Walle nvmem_layout_put(nvmem->layout); 1026f60442ddSSrinivas Kandagatla device_unregister(&nvmem->dev); 1027c1de7f43SBartosz Golaszewski } 1028c1de7f43SBartosz Golaszewski 1029eace75cfSSrinivas Kandagatla /** 1030eace75cfSSrinivas Kandagatla * nvmem_unregister() - Unregister previously registered nvmem device 1031eace75cfSSrinivas Kandagatla * 1032eace75cfSSrinivas Kandagatla * @nvmem: Pointer to previously registered nvmem device. 1033eace75cfSSrinivas Kandagatla */ 1034bf58e882SBartosz Golaszewski void nvmem_unregister(struct nvmem_device *nvmem) 1035eace75cfSSrinivas Kandagatla { 10368c751e0dSAndy Shevchenko if (nvmem) 1037c1de7f43SBartosz Golaszewski kref_put(&nvmem->refcnt, nvmem_device_release); 1038eace75cfSSrinivas Kandagatla } 1039eace75cfSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_unregister); 1040eace75cfSSrinivas Kandagatla 10415825b2c6SAndy Shevchenko static void devm_nvmem_unregister(void *nvmem) 1042f1f50ecaSAndrey Smirnov { 10435825b2c6SAndy Shevchenko nvmem_unregister(nvmem); 1044f1f50ecaSAndrey Smirnov } 1045f1f50ecaSAndrey Smirnov 1046f1f50ecaSAndrey Smirnov /** 1047f1f50ecaSAndrey Smirnov * devm_nvmem_register() - Register a managed nvmem device for given 1048f1f50ecaSAndrey Smirnov * nvmem_config. 10493a758071SAndreas Färber * Also creates a binary entry in /sys/bus/nvmem/devices/dev-name/nvmem 1050f1f50ecaSAndrey Smirnov * 1051b378c779SSrinivas Kandagatla * @dev: Device that uses the nvmem device. 1052f1f50ecaSAndrey Smirnov * @config: nvmem device configuration with which nvmem device is created. 1053f1f50ecaSAndrey Smirnov * 1054f1f50ecaSAndrey Smirnov * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device 1055f1f50ecaSAndrey Smirnov * on success. 1056f1f50ecaSAndrey Smirnov */ 1057f1f50ecaSAndrey Smirnov struct nvmem_device *devm_nvmem_register(struct device *dev, 1058f1f50ecaSAndrey Smirnov const struct nvmem_config *config) 1059f1f50ecaSAndrey Smirnov { 10605825b2c6SAndy Shevchenko struct nvmem_device *nvmem; 10615825b2c6SAndy Shevchenko int ret; 1062f1f50ecaSAndrey Smirnov 1063f1f50ecaSAndrey Smirnov nvmem = nvmem_register(config); 10645825b2c6SAndy Shevchenko if (IS_ERR(nvmem)) 10655825b2c6SAndy Shevchenko return nvmem; 1066f1f50ecaSAndrey Smirnov 10675825b2c6SAndy Shevchenko ret = devm_add_action_or_reset(dev, devm_nvmem_unregister, nvmem); 10685825b2c6SAndy Shevchenko if (ret) 10695825b2c6SAndy Shevchenko return ERR_PTR(ret); 1070f1f50ecaSAndrey Smirnov 1071f1f50ecaSAndrey Smirnov return nvmem; 1072f1f50ecaSAndrey Smirnov } 1073f1f50ecaSAndrey Smirnov EXPORT_SYMBOL_GPL(devm_nvmem_register); 1074f1f50ecaSAndrey Smirnov 10758c2a2b8cSThomas Bogendoerfer static struct nvmem_device *__nvmem_device_get(void *data, 10768c2a2b8cSThomas Bogendoerfer int (*match)(struct device *dev, const void *data)) 107769aba794SSrinivas Kandagatla { 107869aba794SSrinivas Kandagatla struct nvmem_device *nvmem = NULL; 10798c2a2b8cSThomas Bogendoerfer struct device *dev; 108069aba794SSrinivas Kandagatla 1081c7235ee3SBartosz Golaszewski mutex_lock(&nvmem_mutex); 10828c2a2b8cSThomas Bogendoerfer dev = bus_find_device(&nvmem_bus_type, NULL, data, match); 10838c2a2b8cSThomas Bogendoerfer if (dev) 10848c2a2b8cSThomas Bogendoerfer nvmem = to_nvmem_device(dev); 108569aba794SSrinivas Kandagatla mutex_unlock(&nvmem_mutex); 1086c7235ee3SBartosz Golaszewski if (!nvmem) 1087c7235ee3SBartosz Golaszewski return ERR_PTR(-EPROBE_DEFER); 108869aba794SSrinivas Kandagatla 108969aba794SSrinivas Kandagatla if (!try_module_get(nvmem->owner)) { 109069aba794SSrinivas Kandagatla dev_err(&nvmem->dev, 109169aba794SSrinivas Kandagatla "could not increase module refcount for cell %s\n", 10925db652c9SBartosz Golaszewski nvmem_dev_name(nvmem)); 109369aba794SSrinivas Kandagatla 109473e9dc4dSAlban Bedel put_device(&nvmem->dev); 109569aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 109669aba794SSrinivas Kandagatla } 109769aba794SSrinivas Kandagatla 1098c1de7f43SBartosz Golaszewski kref_get(&nvmem->refcnt); 1099c1de7f43SBartosz Golaszewski 110069aba794SSrinivas Kandagatla return nvmem; 110169aba794SSrinivas Kandagatla } 110269aba794SSrinivas Kandagatla 110369aba794SSrinivas Kandagatla static void __nvmem_device_put(struct nvmem_device *nvmem) 110469aba794SSrinivas Kandagatla { 110573e9dc4dSAlban Bedel put_device(&nvmem->dev); 110669aba794SSrinivas Kandagatla module_put(nvmem->owner); 1107c1de7f43SBartosz Golaszewski kref_put(&nvmem->refcnt, nvmem_device_release); 110869aba794SSrinivas Kandagatla } 110969aba794SSrinivas Kandagatla 1110e701c67cSMasahiro Yamada #if IS_ENABLED(CONFIG_OF) 1111e2a5402eSSrinivas Kandagatla /** 1112e2a5402eSSrinivas Kandagatla * of_nvmem_device_get() - Get nvmem device from a given id 1113e2a5402eSSrinivas Kandagatla * 111429143268SVivek Gautam * @np: Device tree node that uses the nvmem device. 1115e2a5402eSSrinivas Kandagatla * @id: nvmem name from nvmem-names property. 1116e2a5402eSSrinivas Kandagatla * 1117e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device 1118e2a5402eSSrinivas Kandagatla * on success. 1119e2a5402eSSrinivas Kandagatla */ 1120e2a5402eSSrinivas Kandagatla struct nvmem_device *of_nvmem_device_get(struct device_node *np, const char *id) 1121e2a5402eSSrinivas Kandagatla { 1122e2a5402eSSrinivas Kandagatla 1123e2a5402eSSrinivas Kandagatla struct device_node *nvmem_np; 1124b1c194dcSVadym Kochan struct nvmem_device *nvmem; 1125d4e7fef1SAlban Bedel int index = 0; 1126e2a5402eSSrinivas Kandagatla 1127d4e7fef1SAlban Bedel if (id) 1128e2a5402eSSrinivas Kandagatla index = of_property_match_string(np, "nvmem-names", id); 1129e2a5402eSSrinivas Kandagatla 1130e2a5402eSSrinivas Kandagatla nvmem_np = of_parse_phandle(np, "nvmem", index); 1131e2a5402eSSrinivas Kandagatla if (!nvmem_np) 1132d4e7fef1SAlban Bedel return ERR_PTR(-ENOENT); 1133e2a5402eSSrinivas Kandagatla 1134b1c194dcSVadym Kochan nvmem = __nvmem_device_get(nvmem_np, device_match_of_node); 1135b1c194dcSVadym Kochan of_node_put(nvmem_np); 1136b1c194dcSVadym Kochan return nvmem; 1137e2a5402eSSrinivas Kandagatla } 1138e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_nvmem_device_get); 1139e2a5402eSSrinivas Kandagatla #endif 1140e2a5402eSSrinivas Kandagatla 1141e2a5402eSSrinivas Kandagatla /** 1142e2a5402eSSrinivas Kandagatla * nvmem_device_get() - Get nvmem device from a given id 1143e2a5402eSSrinivas Kandagatla * 114429143268SVivek Gautam * @dev: Device that uses the nvmem device. 114529143268SVivek Gautam * @dev_name: name of the requested nvmem device. 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 *nvmem_device_get(struct device *dev, const char *dev_name) 1151e2a5402eSSrinivas Kandagatla { 1152e2a5402eSSrinivas Kandagatla if (dev->of_node) { /* try dt first */ 1153e2a5402eSSrinivas Kandagatla struct nvmem_device *nvmem; 1154e2a5402eSSrinivas Kandagatla 1155e2a5402eSSrinivas Kandagatla nvmem = of_nvmem_device_get(dev->of_node, dev_name); 1156e2a5402eSSrinivas Kandagatla 1157e2a5402eSSrinivas Kandagatla if (!IS_ERR(nvmem) || PTR_ERR(nvmem) == -EPROBE_DEFER) 1158e2a5402eSSrinivas Kandagatla return nvmem; 1159e2a5402eSSrinivas Kandagatla 1160e2a5402eSSrinivas Kandagatla } 1161e2a5402eSSrinivas Kandagatla 11628c2a2b8cSThomas Bogendoerfer return __nvmem_device_get((void *)dev_name, device_match_name); 1163e2a5402eSSrinivas Kandagatla } 1164e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_get); 1165e2a5402eSSrinivas Kandagatla 11668c2a2b8cSThomas Bogendoerfer /** 11678c2a2b8cSThomas Bogendoerfer * nvmem_device_find() - Find nvmem device with matching function 11688c2a2b8cSThomas Bogendoerfer * 11698c2a2b8cSThomas Bogendoerfer * @data: Data to pass to match function 11708c2a2b8cSThomas Bogendoerfer * @match: Callback function to check device 11718c2a2b8cSThomas Bogendoerfer * 11728c2a2b8cSThomas Bogendoerfer * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device 11738c2a2b8cSThomas Bogendoerfer * on success. 11748c2a2b8cSThomas Bogendoerfer */ 11758c2a2b8cSThomas Bogendoerfer struct nvmem_device *nvmem_device_find(void *data, 11768c2a2b8cSThomas Bogendoerfer int (*match)(struct device *dev, const void *data)) 11778c2a2b8cSThomas Bogendoerfer { 11788c2a2b8cSThomas Bogendoerfer return __nvmem_device_get(data, match); 11798c2a2b8cSThomas Bogendoerfer } 11808c2a2b8cSThomas Bogendoerfer EXPORT_SYMBOL_GPL(nvmem_device_find); 11818c2a2b8cSThomas Bogendoerfer 1182e2a5402eSSrinivas Kandagatla static int devm_nvmem_device_match(struct device *dev, void *res, void *data) 1183e2a5402eSSrinivas Kandagatla { 1184e2a5402eSSrinivas Kandagatla struct nvmem_device **nvmem = res; 1185e2a5402eSSrinivas Kandagatla 1186e2a5402eSSrinivas Kandagatla if (WARN_ON(!nvmem || !*nvmem)) 1187e2a5402eSSrinivas Kandagatla return 0; 1188e2a5402eSSrinivas Kandagatla 1189e2a5402eSSrinivas Kandagatla return *nvmem == data; 1190e2a5402eSSrinivas Kandagatla } 1191e2a5402eSSrinivas Kandagatla 1192e2a5402eSSrinivas Kandagatla static void devm_nvmem_device_release(struct device *dev, void *res) 1193e2a5402eSSrinivas Kandagatla { 1194e2a5402eSSrinivas Kandagatla nvmem_device_put(*(struct nvmem_device **)res); 1195e2a5402eSSrinivas Kandagatla } 1196e2a5402eSSrinivas Kandagatla 1197e2a5402eSSrinivas Kandagatla /** 1198e2a5402eSSrinivas Kandagatla * devm_nvmem_device_put() - put alredy got nvmem device 1199e2a5402eSSrinivas Kandagatla * 120029143268SVivek Gautam * @dev: Device that uses the nvmem device. 1201e2a5402eSSrinivas Kandagatla * @nvmem: pointer to nvmem device allocated by devm_nvmem_cell_get(), 1202e2a5402eSSrinivas Kandagatla * that needs to be released. 1203e2a5402eSSrinivas Kandagatla */ 1204e2a5402eSSrinivas Kandagatla void devm_nvmem_device_put(struct device *dev, struct nvmem_device *nvmem) 1205e2a5402eSSrinivas Kandagatla { 1206e2a5402eSSrinivas Kandagatla int ret; 1207e2a5402eSSrinivas Kandagatla 1208e2a5402eSSrinivas Kandagatla ret = devres_release(dev, devm_nvmem_device_release, 1209e2a5402eSSrinivas Kandagatla devm_nvmem_device_match, nvmem); 1210e2a5402eSSrinivas Kandagatla 1211e2a5402eSSrinivas Kandagatla WARN_ON(ret); 1212e2a5402eSSrinivas Kandagatla } 1213e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_device_put); 1214e2a5402eSSrinivas Kandagatla 1215e2a5402eSSrinivas Kandagatla /** 1216e2a5402eSSrinivas Kandagatla * nvmem_device_put() - put alredy got nvmem device 1217e2a5402eSSrinivas Kandagatla * 1218e2a5402eSSrinivas Kandagatla * @nvmem: pointer to nvmem device that needs to be released. 1219e2a5402eSSrinivas Kandagatla */ 1220e2a5402eSSrinivas Kandagatla void nvmem_device_put(struct nvmem_device *nvmem) 1221e2a5402eSSrinivas Kandagatla { 1222e2a5402eSSrinivas Kandagatla __nvmem_device_put(nvmem); 1223e2a5402eSSrinivas Kandagatla } 1224e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_put); 1225e2a5402eSSrinivas Kandagatla 1226e2a5402eSSrinivas Kandagatla /** 1227e2a5402eSSrinivas Kandagatla * devm_nvmem_device_get() - Get nvmem cell of device form a given id 1228e2a5402eSSrinivas Kandagatla * 122929143268SVivek Gautam * @dev: Device that requests the nvmem device. 123029143268SVivek Gautam * @id: name id for the requested nvmem device. 1231e2a5402eSSrinivas Kandagatla * 1232e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_cell 1233e2a5402eSSrinivas Kandagatla * on success. The nvmem_cell will be freed by the automatically once the 1234e2a5402eSSrinivas Kandagatla * device is freed. 1235e2a5402eSSrinivas Kandagatla */ 1236e2a5402eSSrinivas Kandagatla struct nvmem_device *devm_nvmem_device_get(struct device *dev, const char *id) 1237e2a5402eSSrinivas Kandagatla { 1238e2a5402eSSrinivas Kandagatla struct nvmem_device **ptr, *nvmem; 1239e2a5402eSSrinivas Kandagatla 1240e2a5402eSSrinivas Kandagatla ptr = devres_alloc(devm_nvmem_device_release, sizeof(*ptr), GFP_KERNEL); 1241e2a5402eSSrinivas Kandagatla if (!ptr) 1242e2a5402eSSrinivas Kandagatla return ERR_PTR(-ENOMEM); 1243e2a5402eSSrinivas Kandagatla 1244e2a5402eSSrinivas Kandagatla nvmem = nvmem_device_get(dev, id); 1245e2a5402eSSrinivas Kandagatla if (!IS_ERR(nvmem)) { 1246e2a5402eSSrinivas Kandagatla *ptr = nvmem; 1247e2a5402eSSrinivas Kandagatla devres_add(dev, ptr); 1248e2a5402eSSrinivas Kandagatla } else { 1249e2a5402eSSrinivas Kandagatla devres_free(ptr); 1250e2a5402eSSrinivas Kandagatla } 1251e2a5402eSSrinivas Kandagatla 1252e2a5402eSSrinivas Kandagatla return nvmem; 1253e2a5402eSSrinivas Kandagatla } 1254e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_device_get); 1255e2a5402eSSrinivas Kandagatla 12565d8e6e6cSMichael Walle static struct nvmem_cell *nvmem_create_cell(struct nvmem_cell_entry *entry, 12575d8e6e6cSMichael Walle const char *id, int index) 12587ae6478bSSrinivas Kandagatla { 12597ae6478bSSrinivas Kandagatla struct nvmem_cell *cell; 12607ae6478bSSrinivas Kandagatla const char *name = NULL; 12617ae6478bSSrinivas Kandagatla 12627ae6478bSSrinivas Kandagatla cell = kzalloc(sizeof(*cell), GFP_KERNEL); 12637ae6478bSSrinivas Kandagatla if (!cell) 12647ae6478bSSrinivas Kandagatla return ERR_PTR(-ENOMEM); 12657ae6478bSSrinivas Kandagatla 12667ae6478bSSrinivas Kandagatla if (id) { 12677ae6478bSSrinivas Kandagatla name = kstrdup_const(id, GFP_KERNEL); 12687ae6478bSSrinivas Kandagatla if (!name) { 12697ae6478bSSrinivas Kandagatla kfree(cell); 12707ae6478bSSrinivas Kandagatla return ERR_PTR(-ENOMEM); 12717ae6478bSSrinivas Kandagatla } 12727ae6478bSSrinivas Kandagatla } 12737ae6478bSSrinivas Kandagatla 12747ae6478bSSrinivas Kandagatla cell->id = name; 12757ae6478bSSrinivas Kandagatla cell->entry = entry; 12765d8e6e6cSMichael Walle cell->index = index; 12777ae6478bSSrinivas Kandagatla 12787ae6478bSSrinivas Kandagatla return cell; 12797ae6478bSSrinivas Kandagatla } 12807ae6478bSSrinivas Kandagatla 1281506157beSBartosz Golaszewski static struct nvmem_cell * 1282506157beSBartosz Golaszewski nvmem_cell_get_from_lookup(struct device *dev, const char *con_id) 128369aba794SSrinivas Kandagatla { 12847ae6478bSSrinivas Kandagatla struct nvmem_cell_entry *cell_entry; 1285506157beSBartosz Golaszewski struct nvmem_cell *cell = ERR_PTR(-ENOENT); 1286506157beSBartosz Golaszewski struct nvmem_cell_lookup *lookup; 128769aba794SSrinivas Kandagatla struct nvmem_device *nvmem; 1288506157beSBartosz Golaszewski const char *dev_id; 128969aba794SSrinivas Kandagatla 1290506157beSBartosz Golaszewski if (!dev) 1291506157beSBartosz Golaszewski return ERR_PTR(-EINVAL); 129269aba794SSrinivas Kandagatla 1293506157beSBartosz Golaszewski dev_id = dev_name(dev); 1294506157beSBartosz Golaszewski 1295506157beSBartosz Golaszewski mutex_lock(&nvmem_lookup_mutex); 1296506157beSBartosz Golaszewski 1297506157beSBartosz Golaszewski list_for_each_entry(lookup, &nvmem_lookup_list, node) { 1298506157beSBartosz Golaszewski if ((strcmp(lookup->dev_id, dev_id) == 0) && 1299506157beSBartosz Golaszewski (strcmp(lookup->con_id, con_id) == 0)) { 1300506157beSBartosz Golaszewski /* This is the right entry. */ 13018c2a2b8cSThomas Bogendoerfer nvmem = __nvmem_device_get((void *)lookup->nvmem_name, 13028c2a2b8cSThomas Bogendoerfer device_match_name); 1303cccb3b19SBartosz Golaszewski if (IS_ERR(nvmem)) { 1304506157beSBartosz Golaszewski /* Provider may not be registered yet. */ 1305cccb3b19SBartosz Golaszewski cell = ERR_CAST(nvmem); 13069bfd8198SAlban Bedel break; 1307506157beSBartosz Golaszewski } 1308506157beSBartosz Golaszewski 13097ae6478bSSrinivas Kandagatla cell_entry = nvmem_find_cell_entry_by_name(nvmem, 1310506157beSBartosz Golaszewski lookup->cell_name); 13117ae6478bSSrinivas Kandagatla if (!cell_entry) { 1312506157beSBartosz Golaszewski __nvmem_device_put(nvmem); 1313cccb3b19SBartosz Golaszewski cell = ERR_PTR(-ENOENT); 13147ae6478bSSrinivas Kandagatla } else { 13155d8e6e6cSMichael Walle cell = nvmem_create_cell(cell_entry, con_id, 0); 13167ae6478bSSrinivas Kandagatla if (IS_ERR(cell)) 13177ae6478bSSrinivas Kandagatla __nvmem_device_put(nvmem); 1318506157beSBartosz Golaszewski } 13199bfd8198SAlban Bedel break; 1320506157beSBartosz Golaszewski } 1321506157beSBartosz Golaszewski } 1322506157beSBartosz Golaszewski 1323506157beSBartosz Golaszewski mutex_unlock(&nvmem_lookup_mutex); 132469aba794SSrinivas Kandagatla return cell; 132569aba794SSrinivas Kandagatla } 132669aba794SSrinivas Kandagatla 1327e701c67cSMasahiro Yamada #if IS_ENABLED(CONFIG_OF) 13287ae6478bSSrinivas Kandagatla static struct nvmem_cell_entry * 13297ae6478bSSrinivas Kandagatla nvmem_find_cell_entry_by_node(struct nvmem_device *nvmem, struct device_node *np) 13303c53e235SArnd Bergmann { 13317ae6478bSSrinivas Kandagatla struct nvmem_cell_entry *iter, *cell = NULL; 13323c53e235SArnd Bergmann 13333c53e235SArnd Bergmann mutex_lock(&nvmem_mutex); 13341c832674SAlban Bedel list_for_each_entry(iter, &nvmem->cells, node) { 13351c832674SAlban Bedel if (np == iter->np) { 13361c832674SAlban Bedel cell = iter; 13373c53e235SArnd Bergmann break; 13383c53e235SArnd Bergmann } 13391c832674SAlban Bedel } 13403c53e235SArnd Bergmann mutex_unlock(&nvmem_mutex); 13413c53e235SArnd Bergmann 13423c53e235SArnd Bergmann return cell; 13433c53e235SArnd Bergmann } 13443c53e235SArnd Bergmann 134569aba794SSrinivas Kandagatla /** 134669aba794SSrinivas Kandagatla * of_nvmem_cell_get() - Get a nvmem cell from given device node and cell id 134769aba794SSrinivas Kandagatla * 134829143268SVivek Gautam * @np: Device tree node that uses the nvmem cell. 1349165589f0SBartosz Golaszewski * @id: nvmem cell name from nvmem-cell-names property, or NULL 1350fd0c478cSVivek Gautam * for the cell at index 0 (the lone cell with no accompanying 1351fd0c478cSVivek Gautam * nvmem-cell-names property). 135269aba794SSrinivas Kandagatla * 135369aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 135469aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 135569aba794SSrinivas Kandagatla * nvmem_cell_put(). 135669aba794SSrinivas Kandagatla */ 1357165589f0SBartosz Golaszewski struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *id) 135869aba794SSrinivas Kandagatla { 135969aba794SSrinivas Kandagatla struct device_node *cell_np, *nvmem_np; 136069aba794SSrinivas Kandagatla struct nvmem_device *nvmem; 13617ae6478bSSrinivas Kandagatla struct nvmem_cell_entry *cell_entry; 1362e888d445SBartosz Golaszewski struct nvmem_cell *cell; 13635d8e6e6cSMichael Walle struct of_phandle_args cell_spec; 1364fd0c478cSVivek Gautam int index = 0; 13655d8e6e6cSMichael Walle int cell_index = 0; 13665d8e6e6cSMichael Walle int ret; 136769aba794SSrinivas Kandagatla 1368fd0c478cSVivek Gautam /* if cell name exists, find index to the name */ 1369165589f0SBartosz Golaszewski if (id) 1370165589f0SBartosz Golaszewski index = of_property_match_string(np, "nvmem-cell-names", id); 137169aba794SSrinivas Kandagatla 13725d8e6e6cSMichael Walle ret = of_parse_phandle_with_optional_args(np, "nvmem-cells", 13735d8e6e6cSMichael Walle "#nvmem-cell-cells", 13745d8e6e6cSMichael Walle index, &cell_spec); 13755d8e6e6cSMichael Walle if (ret) 137606be6208SMichael Walle return ERR_PTR(-ENOENT); 13775d8e6e6cSMichael Walle 13785d8e6e6cSMichael Walle if (cell_spec.args_count > 1) 13795d8e6e6cSMichael Walle return ERR_PTR(-EINVAL); 13805d8e6e6cSMichael Walle 13815d8e6e6cSMichael Walle cell_np = cell_spec.np; 13825d8e6e6cSMichael Walle if (cell_spec.args_count) 13835d8e6e6cSMichael Walle cell_index = cell_spec.args[0]; 138469aba794SSrinivas Kandagatla 1385edcf2fb6SMichael Walle nvmem_np = of_get_parent(cell_np); 1386edcf2fb6SMichael Walle if (!nvmem_np) { 1387edcf2fb6SMichael Walle of_node_put(cell_np); 138869aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 1389edcf2fb6SMichael Walle } 139069aba794SSrinivas Kandagatla 1391266570f4SMichael Walle /* nvmem layouts produce cells within the nvmem-layout container */ 1392266570f4SMichael Walle if (of_node_name_eq(nvmem_np, "nvmem-layout")) { 1393266570f4SMichael Walle nvmem_np = of_get_next_parent(nvmem_np); 1394266570f4SMichael Walle if (!nvmem_np) { 1395266570f4SMichael Walle of_node_put(cell_np); 1396266570f4SMichael Walle return ERR_PTR(-EINVAL); 1397266570f4SMichael Walle } 1398266570f4SMichael Walle } 1399266570f4SMichael Walle 14008c2a2b8cSThomas Bogendoerfer nvmem = __nvmem_device_get(nvmem_np, device_match_of_node); 1401aad8d097SMasahiro Yamada of_node_put(nvmem_np); 1402edcf2fb6SMichael Walle if (IS_ERR(nvmem)) { 1403edcf2fb6SMichael Walle of_node_put(cell_np); 140469aba794SSrinivas Kandagatla return ERR_CAST(nvmem); 1405edcf2fb6SMichael Walle } 140669aba794SSrinivas Kandagatla 14077ae6478bSSrinivas Kandagatla cell_entry = nvmem_find_cell_entry_by_node(nvmem, cell_np); 1408edcf2fb6SMichael Walle of_node_put(cell_np); 14097ae6478bSSrinivas Kandagatla if (!cell_entry) { 1410e888d445SBartosz Golaszewski __nvmem_device_put(nvmem); 1411e888d445SBartosz Golaszewski return ERR_PTR(-ENOENT); 141269aba794SSrinivas Kandagatla } 141369aba794SSrinivas Kandagatla 14145d8e6e6cSMichael Walle cell = nvmem_create_cell(cell_entry, id, cell_index); 14157ae6478bSSrinivas Kandagatla if (IS_ERR(cell)) 14167ae6478bSSrinivas Kandagatla __nvmem_device_put(nvmem); 14177ae6478bSSrinivas Kandagatla 141869aba794SSrinivas Kandagatla return cell; 141969aba794SSrinivas Kandagatla } 142069aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_nvmem_cell_get); 142169aba794SSrinivas Kandagatla #endif 142269aba794SSrinivas Kandagatla 142369aba794SSrinivas Kandagatla /** 142469aba794SSrinivas Kandagatla * nvmem_cell_get() - Get nvmem cell of device form a given cell name 142569aba794SSrinivas Kandagatla * 142629143268SVivek Gautam * @dev: Device that requests the nvmem cell. 1427165589f0SBartosz Golaszewski * @id: nvmem cell name to get (this corresponds with the name from the 1428165589f0SBartosz Golaszewski * nvmem-cell-names property for DT systems and with the con_id from 1429165589f0SBartosz Golaszewski * the lookup entry for non-DT systems). 143069aba794SSrinivas Kandagatla * 143169aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 143269aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 143369aba794SSrinivas Kandagatla * nvmem_cell_put(). 143469aba794SSrinivas Kandagatla */ 1435165589f0SBartosz Golaszewski struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *id) 143669aba794SSrinivas Kandagatla { 143769aba794SSrinivas Kandagatla struct nvmem_cell *cell; 143869aba794SSrinivas Kandagatla 143969aba794SSrinivas Kandagatla if (dev->of_node) { /* try dt first */ 1440165589f0SBartosz Golaszewski cell = of_nvmem_cell_get(dev->of_node, id); 144169aba794SSrinivas Kandagatla if (!IS_ERR(cell) || PTR_ERR(cell) == -EPROBE_DEFER) 144269aba794SSrinivas Kandagatla return cell; 144369aba794SSrinivas Kandagatla } 144469aba794SSrinivas Kandagatla 1445165589f0SBartosz Golaszewski /* NULL cell id only allowed for device tree; invalid otherwise */ 1446165589f0SBartosz Golaszewski if (!id) 144787ed1405SDouglas Anderson return ERR_PTR(-EINVAL); 144887ed1405SDouglas Anderson 1449165589f0SBartosz Golaszewski return nvmem_cell_get_from_lookup(dev, id); 145069aba794SSrinivas Kandagatla } 145169aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_get); 145269aba794SSrinivas Kandagatla 145369aba794SSrinivas Kandagatla static void devm_nvmem_cell_release(struct device *dev, void *res) 145469aba794SSrinivas Kandagatla { 145569aba794SSrinivas Kandagatla nvmem_cell_put(*(struct nvmem_cell **)res); 145669aba794SSrinivas Kandagatla } 145769aba794SSrinivas Kandagatla 145869aba794SSrinivas Kandagatla /** 145969aba794SSrinivas Kandagatla * devm_nvmem_cell_get() - Get nvmem cell of device form a given id 146069aba794SSrinivas Kandagatla * 146129143268SVivek Gautam * @dev: Device that requests the nvmem cell. 146229143268SVivek Gautam * @id: nvmem cell name id to get. 146369aba794SSrinivas Kandagatla * 146469aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 146569aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 146669aba794SSrinivas Kandagatla * automatically once the device is freed. 146769aba794SSrinivas Kandagatla */ 146869aba794SSrinivas Kandagatla struct nvmem_cell *devm_nvmem_cell_get(struct device *dev, const char *id) 146969aba794SSrinivas Kandagatla { 147069aba794SSrinivas Kandagatla struct nvmem_cell **ptr, *cell; 147169aba794SSrinivas Kandagatla 147269aba794SSrinivas Kandagatla ptr = devres_alloc(devm_nvmem_cell_release, sizeof(*ptr), GFP_KERNEL); 147369aba794SSrinivas Kandagatla if (!ptr) 147469aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 147569aba794SSrinivas Kandagatla 147669aba794SSrinivas Kandagatla cell = nvmem_cell_get(dev, id); 147769aba794SSrinivas Kandagatla if (!IS_ERR(cell)) { 147869aba794SSrinivas Kandagatla *ptr = cell; 147969aba794SSrinivas Kandagatla devres_add(dev, ptr); 148069aba794SSrinivas Kandagatla } else { 148169aba794SSrinivas Kandagatla devres_free(ptr); 148269aba794SSrinivas Kandagatla } 148369aba794SSrinivas Kandagatla 148469aba794SSrinivas Kandagatla return cell; 148569aba794SSrinivas Kandagatla } 148669aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_cell_get); 148769aba794SSrinivas Kandagatla 148869aba794SSrinivas Kandagatla static int devm_nvmem_cell_match(struct device *dev, void *res, void *data) 148969aba794SSrinivas Kandagatla { 149069aba794SSrinivas Kandagatla struct nvmem_cell **c = res; 149169aba794SSrinivas Kandagatla 149269aba794SSrinivas Kandagatla if (WARN_ON(!c || !*c)) 149369aba794SSrinivas Kandagatla return 0; 149469aba794SSrinivas Kandagatla 149569aba794SSrinivas Kandagatla return *c == data; 149669aba794SSrinivas Kandagatla } 149769aba794SSrinivas Kandagatla 149869aba794SSrinivas Kandagatla /** 149969aba794SSrinivas Kandagatla * devm_nvmem_cell_put() - Release previously allocated nvmem cell 150069aba794SSrinivas Kandagatla * from devm_nvmem_cell_get. 150169aba794SSrinivas Kandagatla * 150229143268SVivek Gautam * @dev: Device that requests the nvmem cell. 150329143268SVivek Gautam * @cell: Previously allocated nvmem cell by devm_nvmem_cell_get(). 150469aba794SSrinivas Kandagatla */ 150569aba794SSrinivas Kandagatla void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell) 150669aba794SSrinivas Kandagatla { 150769aba794SSrinivas Kandagatla int ret; 150869aba794SSrinivas Kandagatla 150969aba794SSrinivas Kandagatla ret = devres_release(dev, devm_nvmem_cell_release, 151069aba794SSrinivas Kandagatla devm_nvmem_cell_match, cell); 151169aba794SSrinivas Kandagatla 151269aba794SSrinivas Kandagatla WARN_ON(ret); 151369aba794SSrinivas Kandagatla } 151469aba794SSrinivas Kandagatla EXPORT_SYMBOL(devm_nvmem_cell_put); 151569aba794SSrinivas Kandagatla 151669aba794SSrinivas Kandagatla /** 151769aba794SSrinivas Kandagatla * nvmem_cell_put() - Release previously allocated nvmem cell. 151869aba794SSrinivas Kandagatla * 151929143268SVivek Gautam * @cell: Previously allocated nvmem cell by nvmem_cell_get(). 152069aba794SSrinivas Kandagatla */ 152169aba794SSrinivas Kandagatla void nvmem_cell_put(struct nvmem_cell *cell) 152269aba794SSrinivas Kandagatla { 15237ae6478bSSrinivas Kandagatla struct nvmem_device *nvmem = cell->entry->nvmem; 152469aba794SSrinivas Kandagatla 15257ae6478bSSrinivas Kandagatla if (cell->id) 15267ae6478bSSrinivas Kandagatla kfree_const(cell->id); 15277ae6478bSSrinivas Kandagatla 15287ae6478bSSrinivas Kandagatla kfree(cell); 152969aba794SSrinivas Kandagatla __nvmem_device_put(nvmem); 153069aba794SSrinivas Kandagatla } 153169aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_put); 153269aba794SSrinivas Kandagatla 15337ae6478bSSrinivas Kandagatla static void nvmem_shift_read_buffer_in_place(struct nvmem_cell_entry *cell, void *buf) 153469aba794SSrinivas Kandagatla { 153569aba794SSrinivas Kandagatla u8 *p, *b; 15362fe518feSJorge Ramirez-Ortiz int i, extra, bit_offset = cell->bit_offset; 153769aba794SSrinivas Kandagatla 153869aba794SSrinivas Kandagatla p = b = buf; 153969aba794SSrinivas Kandagatla if (bit_offset) { 154069aba794SSrinivas Kandagatla /* First shift */ 154169aba794SSrinivas Kandagatla *b++ >>= bit_offset; 154269aba794SSrinivas Kandagatla 154369aba794SSrinivas Kandagatla /* setup rest of the bytes if any */ 154469aba794SSrinivas Kandagatla for (i = 1; i < cell->bytes; i++) { 154569aba794SSrinivas Kandagatla /* Get bits from next byte and shift them towards msb */ 154669aba794SSrinivas Kandagatla *p |= *b << (BITS_PER_BYTE - bit_offset); 154769aba794SSrinivas Kandagatla 154869aba794SSrinivas Kandagatla p = b; 154969aba794SSrinivas Kandagatla *b++ >>= bit_offset; 155069aba794SSrinivas Kandagatla } 15512fe518feSJorge Ramirez-Ortiz } else { 15522fe518feSJorge Ramirez-Ortiz /* point to the msb */ 15532fe518feSJorge Ramirez-Ortiz p += cell->bytes - 1; 15542fe518feSJorge Ramirez-Ortiz } 155569aba794SSrinivas Kandagatla 155669aba794SSrinivas Kandagatla /* result fits in less bytes */ 15572fe518feSJorge Ramirez-Ortiz extra = cell->bytes - DIV_ROUND_UP(cell->nbits, BITS_PER_BYTE); 15582fe518feSJorge Ramirez-Ortiz while (--extra >= 0) 155969aba794SSrinivas Kandagatla *p-- = 0; 15602fe518feSJorge Ramirez-Ortiz 156169aba794SSrinivas Kandagatla /* clear msb bits if any leftover in the last byte */ 15625d388fa0SStephen Boyd if (cell->nbits % BITS_PER_BYTE) 156369aba794SSrinivas Kandagatla *p &= GENMASK((cell->nbits % BITS_PER_BYTE) - 1, 0); 156469aba794SSrinivas Kandagatla } 156569aba794SSrinivas Kandagatla 156669aba794SSrinivas Kandagatla static int __nvmem_cell_read(struct nvmem_device *nvmem, 15677ae6478bSSrinivas Kandagatla struct nvmem_cell_entry *cell, 15685d8e6e6cSMichael Walle void *buf, size_t *len, const char *id, int index) 156969aba794SSrinivas Kandagatla { 157069aba794SSrinivas Kandagatla int rc; 157169aba794SSrinivas Kandagatla 157255d4980cSRafał Miłecki rc = nvmem_reg_read(nvmem, cell->offset, buf, cell->raw_len); 157369aba794SSrinivas Kandagatla 1574287980e4SArnd Bergmann if (rc) 157569aba794SSrinivas Kandagatla return rc; 157669aba794SSrinivas Kandagatla 157769aba794SSrinivas Kandagatla /* shift bits in-place */ 1578cbf854abSAxel Lin if (cell->bit_offset || cell->nbits) 157969aba794SSrinivas Kandagatla nvmem_shift_read_buffer_in_place(cell, buf); 158069aba794SSrinivas Kandagatla 1581345ec382SMichael Walle if (cell->read_post_process) { 15828a134fd9SMichael Walle rc = cell->read_post_process(cell->priv, id, index, 158355d4980cSRafał Miłecki cell->offset, buf, cell->raw_len); 1584345ec382SMichael Walle if (rc) 1585345ec382SMichael Walle return rc; 1586345ec382SMichael Walle } 1587345ec382SMichael Walle 15883b4a6877SVivek Gautam if (len) 158969aba794SSrinivas Kandagatla *len = cell->bytes; 159069aba794SSrinivas Kandagatla 159169aba794SSrinivas Kandagatla return 0; 159269aba794SSrinivas Kandagatla } 159369aba794SSrinivas Kandagatla 159469aba794SSrinivas Kandagatla /** 159569aba794SSrinivas Kandagatla * nvmem_cell_read() - Read a given nvmem cell 159669aba794SSrinivas Kandagatla * 159769aba794SSrinivas Kandagatla * @cell: nvmem cell to be read. 15983b4a6877SVivek Gautam * @len: pointer to length of cell which will be populated on successful read; 15993b4a6877SVivek Gautam * can be NULL. 160069aba794SSrinivas Kandagatla * 1601b577fafcSBrian Norris * Return: ERR_PTR() on error or a valid pointer to a buffer on success. The 1602b577fafcSBrian Norris * buffer should be freed by the consumer with a kfree(). 160369aba794SSrinivas Kandagatla */ 160469aba794SSrinivas Kandagatla void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len) 160569aba794SSrinivas Kandagatla { 160655d4980cSRafał Miłecki struct nvmem_cell_entry *entry = cell->entry; 160755d4980cSRafał Miłecki struct nvmem_device *nvmem = entry->nvmem; 160869aba794SSrinivas Kandagatla u8 *buf; 160969aba794SSrinivas Kandagatla int rc; 161069aba794SSrinivas Kandagatla 1611795ddd18SSrinivas Kandagatla if (!nvmem) 161269aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 161369aba794SSrinivas Kandagatla 161455d4980cSRafał Miłecki buf = kzalloc(max_t(size_t, entry->raw_len, entry->bytes), GFP_KERNEL); 161569aba794SSrinivas Kandagatla if (!buf) 161669aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 161769aba794SSrinivas Kandagatla 16185d8e6e6cSMichael Walle rc = __nvmem_cell_read(nvmem, cell->entry, buf, len, cell->id, cell->index); 1619287980e4SArnd Bergmann if (rc) { 162069aba794SSrinivas Kandagatla kfree(buf); 162169aba794SSrinivas Kandagatla return ERR_PTR(rc); 162269aba794SSrinivas Kandagatla } 162369aba794SSrinivas Kandagatla 162469aba794SSrinivas Kandagatla return buf; 162569aba794SSrinivas Kandagatla } 162669aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_read); 162769aba794SSrinivas Kandagatla 16287ae6478bSSrinivas Kandagatla static void *nvmem_cell_prepare_write_buffer(struct nvmem_cell_entry *cell, 162969aba794SSrinivas Kandagatla u8 *_buf, int len) 163069aba794SSrinivas Kandagatla { 163169aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 163269aba794SSrinivas Kandagatla int i, rc, nbits, bit_offset = cell->bit_offset; 163369aba794SSrinivas Kandagatla u8 v, *p, *buf, *b, pbyte, pbits; 163469aba794SSrinivas Kandagatla 163569aba794SSrinivas Kandagatla nbits = cell->nbits; 163669aba794SSrinivas Kandagatla buf = kzalloc(cell->bytes, GFP_KERNEL); 163769aba794SSrinivas Kandagatla if (!buf) 163869aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 163969aba794SSrinivas Kandagatla 164069aba794SSrinivas Kandagatla memcpy(buf, _buf, len); 164169aba794SSrinivas Kandagatla p = b = buf; 164269aba794SSrinivas Kandagatla 164369aba794SSrinivas Kandagatla if (bit_offset) { 164469aba794SSrinivas Kandagatla pbyte = *b; 164569aba794SSrinivas Kandagatla *b <<= bit_offset; 164669aba794SSrinivas Kandagatla 164769aba794SSrinivas Kandagatla /* setup the first byte with lsb bits from nvmem */ 1648795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, cell->offset, &v, 1); 164950808bfcSMathieu Malaterre if (rc) 165050808bfcSMathieu Malaterre goto err; 165169aba794SSrinivas Kandagatla *b++ |= GENMASK(bit_offset - 1, 0) & v; 165269aba794SSrinivas Kandagatla 165369aba794SSrinivas Kandagatla /* setup rest of the byte if any */ 165469aba794SSrinivas Kandagatla for (i = 1; i < cell->bytes; i++) { 165569aba794SSrinivas Kandagatla /* Get last byte bits and shift them towards lsb */ 165669aba794SSrinivas Kandagatla pbits = pbyte >> (BITS_PER_BYTE - 1 - bit_offset); 165769aba794SSrinivas Kandagatla pbyte = *b; 165869aba794SSrinivas Kandagatla p = b; 165969aba794SSrinivas Kandagatla *b <<= bit_offset; 166069aba794SSrinivas Kandagatla *b++ |= pbits; 166169aba794SSrinivas Kandagatla } 166269aba794SSrinivas Kandagatla } 166369aba794SSrinivas Kandagatla 166469aba794SSrinivas Kandagatla /* if it's not end on byte boundary */ 166569aba794SSrinivas Kandagatla if ((nbits + bit_offset) % BITS_PER_BYTE) { 166669aba794SSrinivas Kandagatla /* setup the last byte with msb bits from nvmem */ 1667795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, 166869aba794SSrinivas Kandagatla cell->offset + cell->bytes - 1, &v, 1); 166950808bfcSMathieu Malaterre if (rc) 167050808bfcSMathieu Malaterre goto err; 167169aba794SSrinivas Kandagatla *p |= GENMASK(7, (nbits + bit_offset) % BITS_PER_BYTE) & v; 167269aba794SSrinivas Kandagatla 167369aba794SSrinivas Kandagatla } 167469aba794SSrinivas Kandagatla 167569aba794SSrinivas Kandagatla return buf; 167650808bfcSMathieu Malaterre err: 167750808bfcSMathieu Malaterre kfree(buf); 167850808bfcSMathieu Malaterre return ERR_PTR(rc); 167969aba794SSrinivas Kandagatla } 168069aba794SSrinivas Kandagatla 16817ae6478bSSrinivas Kandagatla static int __nvmem_cell_entry_write(struct nvmem_cell_entry *cell, void *buf, size_t len) 168269aba794SSrinivas Kandagatla { 168369aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 168469aba794SSrinivas Kandagatla int rc; 168569aba794SSrinivas Kandagatla 1686795ddd18SSrinivas Kandagatla if (!nvmem || nvmem->read_only || 168769aba794SSrinivas Kandagatla (cell->bit_offset == 0 && len != cell->bytes)) 168869aba794SSrinivas Kandagatla return -EINVAL; 168969aba794SSrinivas Kandagatla 1690345ec382SMichael Walle /* 1691345ec382SMichael Walle * Any cells which have a read_post_process hook are read-only because 1692345ec382SMichael Walle * we cannot reverse the operation and it might affect other cells, 1693345ec382SMichael Walle * too. 1694345ec382SMichael Walle */ 1695345ec382SMichael Walle if (cell->read_post_process) 1696345ec382SMichael Walle return -EINVAL; 1697345ec382SMichael Walle 169869aba794SSrinivas Kandagatla if (cell->bit_offset || cell->nbits) { 169969aba794SSrinivas Kandagatla buf = nvmem_cell_prepare_write_buffer(cell, buf, len); 170069aba794SSrinivas Kandagatla if (IS_ERR(buf)) 170169aba794SSrinivas Kandagatla return PTR_ERR(buf); 170269aba794SSrinivas Kandagatla } 170369aba794SSrinivas Kandagatla 1704795ddd18SSrinivas Kandagatla rc = nvmem_reg_write(nvmem, cell->offset, buf, cell->bytes); 170569aba794SSrinivas Kandagatla 170669aba794SSrinivas Kandagatla /* free the tmp buffer */ 1707ace22170SAxel Lin if (cell->bit_offset || cell->nbits) 170869aba794SSrinivas Kandagatla kfree(buf); 170969aba794SSrinivas Kandagatla 1710287980e4SArnd Bergmann if (rc) 171169aba794SSrinivas Kandagatla return rc; 171269aba794SSrinivas Kandagatla 171369aba794SSrinivas Kandagatla return len; 171469aba794SSrinivas Kandagatla } 17157ae6478bSSrinivas Kandagatla 17167ae6478bSSrinivas Kandagatla /** 17177ae6478bSSrinivas Kandagatla * nvmem_cell_write() - Write to a given nvmem cell 17187ae6478bSSrinivas Kandagatla * 17197ae6478bSSrinivas Kandagatla * @cell: nvmem cell to be written. 17207ae6478bSSrinivas Kandagatla * @buf: Buffer to be written. 17217ae6478bSSrinivas Kandagatla * @len: length of buffer to be written to nvmem cell. 17227ae6478bSSrinivas Kandagatla * 17237ae6478bSSrinivas Kandagatla * Return: length of bytes written or negative on failure. 17247ae6478bSSrinivas Kandagatla */ 17257ae6478bSSrinivas Kandagatla int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len) 17267ae6478bSSrinivas Kandagatla { 17277ae6478bSSrinivas Kandagatla return __nvmem_cell_entry_write(cell->entry, buf, len); 17287ae6478bSSrinivas Kandagatla } 17297ae6478bSSrinivas Kandagatla 173069aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_write); 173169aba794SSrinivas Kandagatla 17326bb317ceSYangtao Li static int nvmem_cell_read_common(struct device *dev, const char *cell_id, 17336bb317ceSYangtao Li void *val, size_t count) 17340a9b2d1cSFabrice Gasnier { 17350a9b2d1cSFabrice Gasnier struct nvmem_cell *cell; 17360a9b2d1cSFabrice Gasnier void *buf; 17370a9b2d1cSFabrice Gasnier size_t len; 17380a9b2d1cSFabrice Gasnier 17390a9b2d1cSFabrice Gasnier cell = nvmem_cell_get(dev, cell_id); 17400a9b2d1cSFabrice Gasnier if (IS_ERR(cell)) 17410a9b2d1cSFabrice Gasnier return PTR_ERR(cell); 17420a9b2d1cSFabrice Gasnier 17430a9b2d1cSFabrice Gasnier buf = nvmem_cell_read(cell, &len); 17440a9b2d1cSFabrice Gasnier if (IS_ERR(buf)) { 17450a9b2d1cSFabrice Gasnier nvmem_cell_put(cell); 17460a9b2d1cSFabrice Gasnier return PTR_ERR(buf); 17470a9b2d1cSFabrice Gasnier } 17486bb317ceSYangtao Li if (len != count) { 17490a9b2d1cSFabrice Gasnier kfree(buf); 17500a9b2d1cSFabrice Gasnier nvmem_cell_put(cell); 17510a9b2d1cSFabrice Gasnier return -EINVAL; 17520a9b2d1cSFabrice Gasnier } 17536bb317ceSYangtao Li memcpy(val, buf, count); 17540a9b2d1cSFabrice Gasnier kfree(buf); 17550a9b2d1cSFabrice Gasnier nvmem_cell_put(cell); 17560a9b2d1cSFabrice Gasnier 17570a9b2d1cSFabrice Gasnier return 0; 17580a9b2d1cSFabrice Gasnier } 17596bb317ceSYangtao Li 17606bb317ceSYangtao Li /** 17615037d368SAndreas Färber * nvmem_cell_read_u8() - Read a cell value as a u8 17625037d368SAndreas Färber * 17635037d368SAndreas Färber * @dev: Device that requests the nvmem cell. 17645037d368SAndreas Färber * @cell_id: Name of nvmem cell to read. 17655037d368SAndreas Färber * @val: pointer to output value. 17665037d368SAndreas Färber * 17675037d368SAndreas Färber * Return: 0 on success or negative errno. 17685037d368SAndreas Färber */ 17695037d368SAndreas Färber int nvmem_cell_read_u8(struct device *dev, const char *cell_id, u8 *val) 17705037d368SAndreas Färber { 17715037d368SAndreas Färber return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val)); 17725037d368SAndreas Färber } 17735037d368SAndreas Färber EXPORT_SYMBOL_GPL(nvmem_cell_read_u8); 17745037d368SAndreas Färber 17755037d368SAndreas Färber /** 17763a758071SAndreas Färber * nvmem_cell_read_u16() - Read a cell value as a u16 17776bb317ceSYangtao Li * 17786bb317ceSYangtao Li * @dev: Device that requests the nvmem cell. 17796bb317ceSYangtao Li * @cell_id: Name of nvmem cell to read. 17806bb317ceSYangtao Li * @val: pointer to output value. 17816bb317ceSYangtao Li * 17826bb317ceSYangtao Li * Return: 0 on success or negative errno. 17836bb317ceSYangtao Li */ 17846bb317ceSYangtao Li int nvmem_cell_read_u16(struct device *dev, const char *cell_id, u16 *val) 17856bb317ceSYangtao Li { 17866bb317ceSYangtao Li return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val)); 17876bb317ceSYangtao Li } 17880a9b2d1cSFabrice Gasnier EXPORT_SYMBOL_GPL(nvmem_cell_read_u16); 17890a9b2d1cSFabrice Gasnier 17900a9b2d1cSFabrice Gasnier /** 17913a758071SAndreas Färber * nvmem_cell_read_u32() - Read a cell value as a u32 1792d026d70aSLeonard Crestez * 1793d026d70aSLeonard Crestez * @dev: Device that requests the nvmem cell. 1794d026d70aSLeonard Crestez * @cell_id: Name of nvmem cell to read. 1795d026d70aSLeonard Crestez * @val: pointer to output value. 1796d026d70aSLeonard Crestez * 1797d026d70aSLeonard Crestez * Return: 0 on success or negative errno. 1798d026d70aSLeonard Crestez */ 1799d026d70aSLeonard Crestez int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val) 1800d026d70aSLeonard Crestez { 18016bb317ceSYangtao Li return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val)); 1802d026d70aSLeonard Crestez } 1803d026d70aSLeonard Crestez EXPORT_SYMBOL_GPL(nvmem_cell_read_u32); 1804d026d70aSLeonard Crestez 1805d026d70aSLeonard Crestez /** 18063a758071SAndreas Färber * nvmem_cell_read_u64() - Read a cell value as a u64 18078b977c54SYangtao Li * 18088b977c54SYangtao Li * @dev: Device that requests the nvmem cell. 18098b977c54SYangtao Li * @cell_id: Name of nvmem cell to read. 18108b977c54SYangtao Li * @val: pointer to output value. 18118b977c54SYangtao Li * 18128b977c54SYangtao Li * Return: 0 on success or negative errno. 18138b977c54SYangtao Li */ 18148b977c54SYangtao Li int nvmem_cell_read_u64(struct device *dev, const char *cell_id, u64 *val) 18158b977c54SYangtao Li { 18168b977c54SYangtao Li return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val)); 18178b977c54SYangtao Li } 18188b977c54SYangtao Li EXPORT_SYMBOL_GPL(nvmem_cell_read_u64); 18198b977c54SYangtao Li 18201f7b4d87SDouglas Anderson static const void *nvmem_cell_read_variable_common(struct device *dev, 1821a28e824fSDouglas Anderson const char *cell_id, 1822a28e824fSDouglas Anderson size_t max_len, size_t *len) 1823a28e824fSDouglas Anderson { 1824a28e824fSDouglas Anderson struct nvmem_cell *cell; 1825a28e824fSDouglas Anderson int nbits; 1826a28e824fSDouglas Anderson void *buf; 1827a28e824fSDouglas Anderson 1828a28e824fSDouglas Anderson cell = nvmem_cell_get(dev, cell_id); 1829a28e824fSDouglas Anderson if (IS_ERR(cell)) 1830a28e824fSDouglas Anderson return cell; 1831a28e824fSDouglas Anderson 18327ae6478bSSrinivas Kandagatla nbits = cell->entry->nbits; 1833a28e824fSDouglas Anderson buf = nvmem_cell_read(cell, len); 1834a28e824fSDouglas Anderson nvmem_cell_put(cell); 1835a28e824fSDouglas Anderson if (IS_ERR(buf)) 1836a28e824fSDouglas Anderson return buf; 1837a28e824fSDouglas Anderson 1838a28e824fSDouglas Anderson /* 1839a28e824fSDouglas Anderson * If nbits is set then nvmem_cell_read() can significantly exaggerate 1840a28e824fSDouglas Anderson * the length of the real data. Throw away the extra junk. 1841a28e824fSDouglas Anderson */ 1842a28e824fSDouglas Anderson if (nbits) 1843a28e824fSDouglas Anderson *len = DIV_ROUND_UP(nbits, 8); 1844a28e824fSDouglas Anderson 1845a28e824fSDouglas Anderson if (*len > max_len) { 1846a28e824fSDouglas Anderson kfree(buf); 1847a28e824fSDouglas Anderson return ERR_PTR(-ERANGE); 1848a28e824fSDouglas Anderson } 1849a28e824fSDouglas Anderson 1850a28e824fSDouglas Anderson return buf; 1851a28e824fSDouglas Anderson } 1852a28e824fSDouglas Anderson 1853a28e824fSDouglas Anderson /** 1854a28e824fSDouglas Anderson * nvmem_cell_read_variable_le_u32() - Read up to 32-bits of data as a little endian number. 1855a28e824fSDouglas Anderson * 1856a28e824fSDouglas Anderson * @dev: Device that requests the nvmem cell. 1857a28e824fSDouglas Anderson * @cell_id: Name of nvmem cell to read. 1858a28e824fSDouglas Anderson * @val: pointer to output value. 1859a28e824fSDouglas Anderson * 1860a28e824fSDouglas Anderson * Return: 0 on success or negative errno. 1861a28e824fSDouglas Anderson */ 1862a28e824fSDouglas Anderson int nvmem_cell_read_variable_le_u32(struct device *dev, const char *cell_id, 1863a28e824fSDouglas Anderson u32 *val) 1864a28e824fSDouglas Anderson { 1865a28e824fSDouglas Anderson size_t len; 18661f7b4d87SDouglas Anderson const u8 *buf; 1867a28e824fSDouglas Anderson int i; 1868a28e824fSDouglas Anderson 1869a28e824fSDouglas Anderson buf = nvmem_cell_read_variable_common(dev, cell_id, sizeof(*val), &len); 1870a28e824fSDouglas Anderson if (IS_ERR(buf)) 1871a28e824fSDouglas Anderson return PTR_ERR(buf); 1872a28e824fSDouglas Anderson 1873a28e824fSDouglas Anderson /* Copy w/ implicit endian conversion */ 1874a28e824fSDouglas Anderson *val = 0; 1875a28e824fSDouglas Anderson for (i = 0; i < len; i++) 1876a28e824fSDouglas Anderson *val |= buf[i] << (8 * i); 1877a28e824fSDouglas Anderson 1878a28e824fSDouglas Anderson kfree(buf); 1879a28e824fSDouglas Anderson 1880a28e824fSDouglas Anderson return 0; 1881a28e824fSDouglas Anderson } 1882a28e824fSDouglas Anderson EXPORT_SYMBOL_GPL(nvmem_cell_read_variable_le_u32); 1883a28e824fSDouglas Anderson 1884a28e824fSDouglas Anderson /** 1885a28e824fSDouglas Anderson * nvmem_cell_read_variable_le_u64() - Read up to 64-bits of data as a little endian number. 1886a28e824fSDouglas Anderson * 1887a28e824fSDouglas Anderson * @dev: Device that requests the nvmem cell. 1888a28e824fSDouglas Anderson * @cell_id: Name of nvmem cell to read. 1889a28e824fSDouglas Anderson * @val: pointer to output value. 1890a28e824fSDouglas Anderson * 1891a28e824fSDouglas Anderson * Return: 0 on success or negative errno. 1892a28e824fSDouglas Anderson */ 1893a28e824fSDouglas Anderson int nvmem_cell_read_variable_le_u64(struct device *dev, const char *cell_id, 1894a28e824fSDouglas Anderson u64 *val) 1895a28e824fSDouglas Anderson { 1896a28e824fSDouglas Anderson size_t len; 18971f7b4d87SDouglas Anderson const u8 *buf; 1898a28e824fSDouglas Anderson int i; 1899a28e824fSDouglas Anderson 1900a28e824fSDouglas Anderson buf = nvmem_cell_read_variable_common(dev, cell_id, sizeof(*val), &len); 1901a28e824fSDouglas Anderson if (IS_ERR(buf)) 1902a28e824fSDouglas Anderson return PTR_ERR(buf); 1903a28e824fSDouglas Anderson 1904a28e824fSDouglas Anderson /* Copy w/ implicit endian conversion */ 1905a28e824fSDouglas Anderson *val = 0; 1906a28e824fSDouglas Anderson for (i = 0; i < len; i++) 190755022fdeSColin Ian King *val |= (uint64_t)buf[i] << (8 * i); 1908a28e824fSDouglas Anderson 1909a28e824fSDouglas Anderson kfree(buf); 1910a28e824fSDouglas Anderson 1911a28e824fSDouglas Anderson return 0; 1912a28e824fSDouglas Anderson } 1913a28e824fSDouglas Anderson EXPORT_SYMBOL_GPL(nvmem_cell_read_variable_le_u64); 1914a28e824fSDouglas Anderson 19158b977c54SYangtao Li /** 1916e2a5402eSSrinivas Kandagatla * nvmem_device_cell_read() - Read a given nvmem device and cell 1917e2a5402eSSrinivas Kandagatla * 1918e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to read from. 1919e2a5402eSSrinivas Kandagatla * @info: nvmem cell info to be read. 1920e2a5402eSSrinivas Kandagatla * @buf: buffer pointer which will be populated on successful read. 1921e2a5402eSSrinivas Kandagatla * 1922e2a5402eSSrinivas Kandagatla * Return: length of successful bytes read on success and negative 1923e2a5402eSSrinivas Kandagatla * error code on error. 1924e2a5402eSSrinivas Kandagatla */ 1925e2a5402eSSrinivas Kandagatla ssize_t nvmem_device_cell_read(struct nvmem_device *nvmem, 1926e2a5402eSSrinivas Kandagatla struct nvmem_cell_info *info, void *buf) 1927e2a5402eSSrinivas Kandagatla { 19287ae6478bSSrinivas Kandagatla struct nvmem_cell_entry cell; 1929e2a5402eSSrinivas Kandagatla int rc; 1930e2a5402eSSrinivas Kandagatla ssize_t len; 1931e2a5402eSSrinivas Kandagatla 1932795ddd18SSrinivas Kandagatla if (!nvmem) 1933e2a5402eSSrinivas Kandagatla return -EINVAL; 1934e2a5402eSSrinivas Kandagatla 19357ae6478bSSrinivas Kandagatla rc = nvmem_cell_info_to_nvmem_cell_entry_nodup(nvmem, info, &cell); 1936287980e4SArnd Bergmann if (rc) 1937e2a5402eSSrinivas Kandagatla return rc; 1938e2a5402eSSrinivas Kandagatla 19395d8e6e6cSMichael Walle rc = __nvmem_cell_read(nvmem, &cell, buf, &len, NULL, 0); 1940287980e4SArnd Bergmann if (rc) 1941e2a5402eSSrinivas Kandagatla return rc; 1942e2a5402eSSrinivas Kandagatla 1943e2a5402eSSrinivas Kandagatla return len; 1944e2a5402eSSrinivas Kandagatla } 1945e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_cell_read); 1946e2a5402eSSrinivas Kandagatla 1947e2a5402eSSrinivas Kandagatla /** 1948e2a5402eSSrinivas Kandagatla * nvmem_device_cell_write() - Write cell to a given nvmem device 1949e2a5402eSSrinivas Kandagatla * 1950e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to be written to. 195129143268SVivek Gautam * @info: nvmem cell info to be written. 1952e2a5402eSSrinivas Kandagatla * @buf: buffer to be written to cell. 1953e2a5402eSSrinivas Kandagatla * 1954e2a5402eSSrinivas Kandagatla * Return: length of bytes written or negative error code on failure. 195548f63a2cSBartosz Golaszewski */ 1956e2a5402eSSrinivas Kandagatla int nvmem_device_cell_write(struct nvmem_device *nvmem, 1957e2a5402eSSrinivas Kandagatla struct nvmem_cell_info *info, void *buf) 1958e2a5402eSSrinivas Kandagatla { 19597ae6478bSSrinivas Kandagatla struct nvmem_cell_entry cell; 1960e2a5402eSSrinivas Kandagatla int rc; 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 19697ae6478bSSrinivas Kandagatla return __nvmem_cell_entry_write(&cell, buf, cell.bytes); 1970e2a5402eSSrinivas Kandagatla } 1971e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_cell_write); 1972e2a5402eSSrinivas Kandagatla 1973e2a5402eSSrinivas Kandagatla /** 1974e2a5402eSSrinivas Kandagatla * nvmem_device_read() - Read from a given nvmem device 1975e2a5402eSSrinivas Kandagatla * 1976e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to read from. 1977e2a5402eSSrinivas Kandagatla * @offset: offset in nvmem device. 1978e2a5402eSSrinivas Kandagatla * @bytes: number of bytes to read. 1979e2a5402eSSrinivas Kandagatla * @buf: buffer pointer which will be populated on successful read. 1980e2a5402eSSrinivas Kandagatla * 1981e2a5402eSSrinivas Kandagatla * Return: length of successful bytes read on success and negative 1982e2a5402eSSrinivas Kandagatla * error code on error. 1983e2a5402eSSrinivas Kandagatla */ 1984e2a5402eSSrinivas Kandagatla int nvmem_device_read(struct nvmem_device *nvmem, 1985e2a5402eSSrinivas Kandagatla unsigned int offset, 1986e2a5402eSSrinivas Kandagatla size_t bytes, void *buf) 1987e2a5402eSSrinivas Kandagatla { 1988e2a5402eSSrinivas Kandagatla int rc; 1989e2a5402eSSrinivas Kandagatla 1990795ddd18SSrinivas Kandagatla if (!nvmem) 1991e2a5402eSSrinivas Kandagatla return -EINVAL; 1992e2a5402eSSrinivas Kandagatla 1993795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, offset, buf, bytes); 1994e2a5402eSSrinivas Kandagatla 1995287980e4SArnd Bergmann if (rc) 1996e2a5402eSSrinivas Kandagatla return rc; 1997e2a5402eSSrinivas Kandagatla 1998e2a5402eSSrinivas Kandagatla return bytes; 1999e2a5402eSSrinivas Kandagatla } 2000e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_read); 2001e2a5402eSSrinivas Kandagatla 2002e2a5402eSSrinivas Kandagatla /** 2003e2a5402eSSrinivas Kandagatla * nvmem_device_write() - Write cell to a given nvmem device 2004e2a5402eSSrinivas Kandagatla * 2005e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to be written to. 2006e2a5402eSSrinivas Kandagatla * @offset: offset in nvmem device. 2007e2a5402eSSrinivas Kandagatla * @bytes: number of bytes to write. 2008e2a5402eSSrinivas Kandagatla * @buf: buffer to be written. 2009e2a5402eSSrinivas Kandagatla * 2010e2a5402eSSrinivas Kandagatla * Return: length of bytes written or negative error code on failure. 201148f63a2cSBartosz Golaszewski */ 2012e2a5402eSSrinivas Kandagatla int nvmem_device_write(struct nvmem_device *nvmem, 2013e2a5402eSSrinivas Kandagatla unsigned int offset, 2014e2a5402eSSrinivas Kandagatla size_t bytes, void *buf) 2015e2a5402eSSrinivas Kandagatla { 2016e2a5402eSSrinivas Kandagatla int rc; 2017e2a5402eSSrinivas Kandagatla 2018795ddd18SSrinivas Kandagatla if (!nvmem) 2019e2a5402eSSrinivas Kandagatla return -EINVAL; 2020e2a5402eSSrinivas Kandagatla 2021795ddd18SSrinivas Kandagatla rc = nvmem_reg_write(nvmem, offset, buf, bytes); 2022e2a5402eSSrinivas Kandagatla 2023287980e4SArnd Bergmann if (rc) 2024e2a5402eSSrinivas Kandagatla return rc; 2025e2a5402eSSrinivas Kandagatla 2026e2a5402eSSrinivas Kandagatla 2027e2a5402eSSrinivas Kandagatla return bytes; 2028e2a5402eSSrinivas Kandagatla } 2029e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_write); 2030e2a5402eSSrinivas Kandagatla 2031d7b9fd16SBartosz Golaszewski /** 2032b985f4cbSBartosz Golaszewski * nvmem_add_cell_table() - register a table of cell info entries 2033b985f4cbSBartosz Golaszewski * 2034b985f4cbSBartosz Golaszewski * @table: table of cell info entries 2035b985f4cbSBartosz Golaszewski */ 2036b985f4cbSBartosz Golaszewski void nvmem_add_cell_table(struct nvmem_cell_table *table) 2037b985f4cbSBartosz Golaszewski { 2038b985f4cbSBartosz Golaszewski mutex_lock(&nvmem_cell_mutex); 2039b985f4cbSBartosz Golaszewski list_add_tail(&table->node, &nvmem_cell_tables); 2040b985f4cbSBartosz Golaszewski mutex_unlock(&nvmem_cell_mutex); 2041b985f4cbSBartosz Golaszewski } 2042b985f4cbSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_add_cell_table); 2043b985f4cbSBartosz Golaszewski 2044b985f4cbSBartosz Golaszewski /** 2045b985f4cbSBartosz Golaszewski * nvmem_del_cell_table() - remove a previously registered cell info table 2046b985f4cbSBartosz Golaszewski * 2047b985f4cbSBartosz Golaszewski * @table: table of cell info entries 2048b985f4cbSBartosz Golaszewski */ 2049b985f4cbSBartosz Golaszewski void nvmem_del_cell_table(struct nvmem_cell_table *table) 2050b985f4cbSBartosz Golaszewski { 2051b985f4cbSBartosz Golaszewski mutex_lock(&nvmem_cell_mutex); 2052b985f4cbSBartosz Golaszewski list_del(&table->node); 2053b985f4cbSBartosz Golaszewski mutex_unlock(&nvmem_cell_mutex); 2054b985f4cbSBartosz Golaszewski } 2055b985f4cbSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_del_cell_table); 2056b985f4cbSBartosz Golaszewski 2057b985f4cbSBartosz Golaszewski /** 2058506157beSBartosz Golaszewski * nvmem_add_cell_lookups() - register a list of cell lookup entries 2059506157beSBartosz Golaszewski * 2060506157beSBartosz Golaszewski * @entries: array of cell lookup entries 2061506157beSBartosz Golaszewski * @nentries: number of cell lookup entries in the array 2062506157beSBartosz Golaszewski */ 2063506157beSBartosz Golaszewski void nvmem_add_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries) 2064506157beSBartosz Golaszewski { 2065506157beSBartosz Golaszewski int i; 2066506157beSBartosz Golaszewski 2067506157beSBartosz Golaszewski mutex_lock(&nvmem_lookup_mutex); 2068506157beSBartosz Golaszewski for (i = 0; i < nentries; i++) 2069506157beSBartosz Golaszewski list_add_tail(&entries[i].node, &nvmem_lookup_list); 2070506157beSBartosz Golaszewski mutex_unlock(&nvmem_lookup_mutex); 2071506157beSBartosz Golaszewski } 2072506157beSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_add_cell_lookups); 2073506157beSBartosz Golaszewski 2074506157beSBartosz Golaszewski /** 2075506157beSBartosz Golaszewski * nvmem_del_cell_lookups() - remove a list of previously added cell lookup 2076506157beSBartosz Golaszewski * entries 2077506157beSBartosz Golaszewski * 2078506157beSBartosz Golaszewski * @entries: array of cell lookup entries 2079506157beSBartosz Golaszewski * @nentries: number of cell lookup entries in the array 2080506157beSBartosz Golaszewski */ 2081506157beSBartosz Golaszewski void nvmem_del_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries) 2082506157beSBartosz Golaszewski { 2083506157beSBartosz Golaszewski int i; 2084506157beSBartosz Golaszewski 2085506157beSBartosz Golaszewski mutex_lock(&nvmem_lookup_mutex); 2086506157beSBartosz Golaszewski for (i = 0; i < nentries; i++) 2087506157beSBartosz Golaszewski list_del(&entries[i].node); 2088506157beSBartosz Golaszewski mutex_unlock(&nvmem_lookup_mutex); 2089506157beSBartosz Golaszewski } 2090506157beSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_del_cell_lookups); 2091506157beSBartosz Golaszewski 2092506157beSBartosz Golaszewski /** 2093d7b9fd16SBartosz Golaszewski * nvmem_dev_name() - Get the name of a given nvmem device. 2094d7b9fd16SBartosz Golaszewski * 2095d7b9fd16SBartosz Golaszewski * @nvmem: nvmem device. 2096d7b9fd16SBartosz Golaszewski * 2097d7b9fd16SBartosz Golaszewski * Return: name of the nvmem device. 2098d7b9fd16SBartosz Golaszewski */ 2099d7b9fd16SBartosz Golaszewski const char *nvmem_dev_name(struct nvmem_device *nvmem) 2100d7b9fd16SBartosz Golaszewski { 2101d7b9fd16SBartosz Golaszewski return dev_name(&nvmem->dev); 2102d7b9fd16SBartosz Golaszewski } 2103d7b9fd16SBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_dev_name); 2104d7b9fd16SBartosz Golaszewski 2105eace75cfSSrinivas Kandagatla static int __init nvmem_init(void) 2106eace75cfSSrinivas Kandagatla { 2107eace75cfSSrinivas Kandagatla return bus_register(&nvmem_bus_type); 2108eace75cfSSrinivas Kandagatla } 2109eace75cfSSrinivas Kandagatla 2110eace75cfSSrinivas Kandagatla static void __exit nvmem_exit(void) 2111eace75cfSSrinivas Kandagatla { 2112eace75cfSSrinivas Kandagatla bus_unregister(&nvmem_bus_type); 2113eace75cfSSrinivas Kandagatla } 2114eace75cfSSrinivas Kandagatla 2115eace75cfSSrinivas Kandagatla subsys_initcall(nvmem_init); 2116eace75cfSSrinivas Kandagatla module_exit(nvmem_exit); 2117eace75cfSSrinivas Kandagatla 2118eace75cfSSrinivas Kandagatla MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org"); 2119eace75cfSSrinivas Kandagatla MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com"); 2120eace75cfSSrinivas Kandagatla MODULE_DESCRIPTION("nvmem Driver Core"); 2121