1b1c1db98SBartosz Golaszewski // SPDX-License-Identifier: GPL-2.0 2eace75cfSSrinivas Kandagatla /* 3eace75cfSSrinivas Kandagatla * nvmem framework core. 4eace75cfSSrinivas Kandagatla * 5eace75cfSSrinivas Kandagatla * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org> 6eace75cfSSrinivas Kandagatla * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com> 7eace75cfSSrinivas Kandagatla */ 8eace75cfSSrinivas Kandagatla 9eace75cfSSrinivas Kandagatla #include <linux/device.h> 10eace75cfSSrinivas Kandagatla #include <linux/export.h> 11eace75cfSSrinivas Kandagatla #include <linux/fs.h> 12eace75cfSSrinivas Kandagatla #include <linux/idr.h> 13eace75cfSSrinivas Kandagatla #include <linux/init.h> 14c1de7f43SBartosz Golaszewski #include <linux/kref.h> 15eace75cfSSrinivas Kandagatla #include <linux/module.h> 16eace75cfSSrinivas Kandagatla #include <linux/nvmem-consumer.h> 17eace75cfSSrinivas Kandagatla #include <linux/nvmem-provider.h> 182a127da4SKhouloud Touil #include <linux/gpio/consumer.h> 19eace75cfSSrinivas Kandagatla #include <linux/of.h> 20eace75cfSSrinivas Kandagatla #include <linux/slab.h> 2184400305SSrinivas Kandagatla 2284400305SSrinivas Kandagatla struct nvmem_device { 2384400305SSrinivas Kandagatla struct module *owner; 2484400305SSrinivas Kandagatla struct device dev; 2584400305SSrinivas Kandagatla int stride; 2684400305SSrinivas Kandagatla int word_size; 2784400305SSrinivas Kandagatla int id; 2884400305SSrinivas Kandagatla struct kref refcnt; 2984400305SSrinivas Kandagatla size_t size; 3084400305SSrinivas Kandagatla bool read_only; 3184400305SSrinivas Kandagatla bool root_only; 3284400305SSrinivas Kandagatla int flags; 3384400305SSrinivas Kandagatla enum nvmem_type type; 3484400305SSrinivas Kandagatla struct bin_attribute eeprom; 3584400305SSrinivas Kandagatla struct device *base_dev; 3684400305SSrinivas Kandagatla struct list_head cells; 37fd3bb8f5SEvan Green const struct nvmem_keepout *keepout; 38fd3bb8f5SEvan Green unsigned int nkeepout; 3984400305SSrinivas Kandagatla nvmem_reg_read_t reg_read; 4084400305SSrinivas Kandagatla nvmem_reg_write_t reg_write; 415008062fSSrinivas Kandagatla nvmem_cell_post_process_t cell_post_process; 4284400305SSrinivas Kandagatla struct gpio_desc *wp_gpio; 4384400305SSrinivas Kandagatla void *priv; 4484400305SSrinivas Kandagatla }; 4584400305SSrinivas Kandagatla 4684400305SSrinivas Kandagatla #define to_nvmem_device(d) container_of(d, struct nvmem_device, dev) 4784400305SSrinivas Kandagatla 4884400305SSrinivas Kandagatla #define FLAG_COMPAT BIT(0) 497ae6478bSSrinivas Kandagatla struct nvmem_cell_entry { 50eace75cfSSrinivas Kandagatla const char *name; 51eace75cfSSrinivas Kandagatla int offset; 52eace75cfSSrinivas Kandagatla int bytes; 53eace75cfSSrinivas Kandagatla int bit_offset; 54eace75cfSSrinivas Kandagatla int nbits; 550749aa25SSrinivas Kandagatla struct device_node *np; 56eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem; 57eace75cfSSrinivas Kandagatla struct list_head node; 58eace75cfSSrinivas Kandagatla }; 59eace75cfSSrinivas Kandagatla 607ae6478bSSrinivas Kandagatla struct nvmem_cell { 617ae6478bSSrinivas Kandagatla struct nvmem_cell_entry *entry; 627ae6478bSSrinivas Kandagatla const char *id; 637ae6478bSSrinivas Kandagatla }; 647ae6478bSSrinivas Kandagatla 65eace75cfSSrinivas Kandagatla static DEFINE_MUTEX(nvmem_mutex); 66eace75cfSSrinivas Kandagatla static DEFINE_IDA(nvmem_ida); 67eace75cfSSrinivas Kandagatla 68b985f4cbSBartosz Golaszewski static DEFINE_MUTEX(nvmem_cell_mutex); 69b985f4cbSBartosz Golaszewski static LIST_HEAD(nvmem_cell_tables); 70b985f4cbSBartosz Golaszewski 71506157beSBartosz Golaszewski static DEFINE_MUTEX(nvmem_lookup_mutex); 72506157beSBartosz Golaszewski static LIST_HEAD(nvmem_lookup_list); 73506157beSBartosz Golaszewski 74bee1138bSBartosz Golaszewski static BLOCKING_NOTIFIER_HEAD(nvmem_notifier); 75bee1138bSBartosz Golaszewski 76fd3bb8f5SEvan Green static int __nvmem_reg_read(struct nvmem_device *nvmem, unsigned int offset, 77b96fc541SMichael Auchter void *val, size_t bytes) 78b96fc541SMichael Auchter { 79b96fc541SMichael Auchter if (nvmem->reg_read) 80b96fc541SMichael Auchter return nvmem->reg_read(nvmem->priv, offset, val, bytes); 81b96fc541SMichael Auchter 82b96fc541SMichael Auchter return -EINVAL; 83b96fc541SMichael Auchter } 84b96fc541SMichael Auchter 85fd3bb8f5SEvan Green static int __nvmem_reg_write(struct nvmem_device *nvmem, unsigned int offset, 86b96fc541SMichael Auchter void *val, size_t bytes) 87b96fc541SMichael Auchter { 88b96fc541SMichael Auchter int ret; 89b96fc541SMichael Auchter 90b96fc541SMichael Auchter if (nvmem->reg_write) { 91b96fc541SMichael Auchter gpiod_set_value_cansleep(nvmem->wp_gpio, 0); 92b96fc541SMichael Auchter ret = nvmem->reg_write(nvmem->priv, offset, val, bytes); 93b96fc541SMichael Auchter gpiod_set_value_cansleep(nvmem->wp_gpio, 1); 94b96fc541SMichael Auchter return ret; 95b96fc541SMichael Auchter } 96b96fc541SMichael Auchter 97b96fc541SMichael Auchter return -EINVAL; 98b96fc541SMichael Auchter } 99b96fc541SMichael Auchter 100fd3bb8f5SEvan Green static int nvmem_access_with_keepouts(struct nvmem_device *nvmem, 101fd3bb8f5SEvan Green unsigned int offset, void *val, 102fd3bb8f5SEvan Green size_t bytes, int write) 103fd3bb8f5SEvan Green { 104fd3bb8f5SEvan Green 105fd3bb8f5SEvan Green unsigned int end = offset + bytes; 106fd3bb8f5SEvan Green unsigned int kend, ksize; 107fd3bb8f5SEvan Green const struct nvmem_keepout *keepout = nvmem->keepout; 108fd3bb8f5SEvan Green const struct nvmem_keepout *keepoutend = keepout + nvmem->nkeepout; 109fd3bb8f5SEvan Green int rc; 110fd3bb8f5SEvan Green 111fd3bb8f5SEvan Green /* 112fd3bb8f5SEvan Green * Skip all keepouts before the range being accessed. 113fd3bb8f5SEvan Green * Keepouts are sorted. 114fd3bb8f5SEvan Green */ 115fd3bb8f5SEvan Green while ((keepout < keepoutend) && (keepout->end <= offset)) 116fd3bb8f5SEvan Green keepout++; 117fd3bb8f5SEvan Green 118fd3bb8f5SEvan Green while ((offset < end) && (keepout < keepoutend)) { 119fd3bb8f5SEvan Green /* Access the valid portion before the keepout. */ 120fd3bb8f5SEvan Green if (offset < keepout->start) { 121fd3bb8f5SEvan Green kend = min(end, keepout->start); 122fd3bb8f5SEvan Green ksize = kend - offset; 123fd3bb8f5SEvan Green if (write) 124fd3bb8f5SEvan Green rc = __nvmem_reg_write(nvmem, offset, val, ksize); 125fd3bb8f5SEvan Green else 126fd3bb8f5SEvan Green rc = __nvmem_reg_read(nvmem, offset, val, ksize); 127fd3bb8f5SEvan Green 128fd3bb8f5SEvan Green if (rc) 129fd3bb8f5SEvan Green return rc; 130fd3bb8f5SEvan Green 131fd3bb8f5SEvan Green offset += ksize; 132fd3bb8f5SEvan Green val += ksize; 133fd3bb8f5SEvan Green } 134fd3bb8f5SEvan Green 135fd3bb8f5SEvan Green /* 136fd3bb8f5SEvan Green * Now we're aligned to the start of this keepout zone. Go 137fd3bb8f5SEvan Green * through it. 138fd3bb8f5SEvan Green */ 139fd3bb8f5SEvan Green kend = min(end, keepout->end); 140fd3bb8f5SEvan Green ksize = kend - offset; 141fd3bb8f5SEvan Green if (!write) 142fd3bb8f5SEvan Green memset(val, keepout->value, ksize); 143fd3bb8f5SEvan Green 144fd3bb8f5SEvan Green val += ksize; 145fd3bb8f5SEvan Green offset += ksize; 146fd3bb8f5SEvan Green keepout++; 147fd3bb8f5SEvan Green } 148fd3bb8f5SEvan Green 149fd3bb8f5SEvan Green /* 150fd3bb8f5SEvan Green * If we ran out of keepouts but there's still stuff to do, send it 151fd3bb8f5SEvan Green * down directly 152fd3bb8f5SEvan Green */ 153fd3bb8f5SEvan Green if (offset < end) { 154fd3bb8f5SEvan Green ksize = end - offset; 155fd3bb8f5SEvan Green if (write) 156fd3bb8f5SEvan Green return __nvmem_reg_write(nvmem, offset, val, ksize); 157fd3bb8f5SEvan Green else 158fd3bb8f5SEvan Green return __nvmem_reg_read(nvmem, offset, val, ksize); 159fd3bb8f5SEvan Green } 160fd3bb8f5SEvan Green 161fd3bb8f5SEvan Green return 0; 162fd3bb8f5SEvan Green } 163fd3bb8f5SEvan Green 164fd3bb8f5SEvan Green static int nvmem_reg_read(struct nvmem_device *nvmem, unsigned int offset, 165fd3bb8f5SEvan Green void *val, size_t bytes) 166fd3bb8f5SEvan Green { 167fd3bb8f5SEvan Green if (!nvmem->nkeepout) 168fd3bb8f5SEvan Green return __nvmem_reg_read(nvmem, offset, val, bytes); 169fd3bb8f5SEvan Green 170fd3bb8f5SEvan Green return nvmem_access_with_keepouts(nvmem, offset, val, bytes, false); 171fd3bb8f5SEvan Green } 172fd3bb8f5SEvan Green 173fd3bb8f5SEvan Green static int nvmem_reg_write(struct nvmem_device *nvmem, unsigned int offset, 174fd3bb8f5SEvan Green void *val, size_t bytes) 175fd3bb8f5SEvan Green { 176fd3bb8f5SEvan Green if (!nvmem->nkeepout) 177fd3bb8f5SEvan Green return __nvmem_reg_write(nvmem, offset, val, bytes); 178fd3bb8f5SEvan Green 179fd3bb8f5SEvan Green return nvmem_access_with_keepouts(nvmem, offset, val, bytes, true); 180fd3bb8f5SEvan Green } 181fd3bb8f5SEvan Green 18284400305SSrinivas Kandagatla #ifdef CONFIG_NVMEM_SYSFS 18384400305SSrinivas Kandagatla static const char * const nvmem_type_str[] = { 18484400305SSrinivas Kandagatla [NVMEM_TYPE_UNKNOWN] = "Unknown", 18584400305SSrinivas Kandagatla [NVMEM_TYPE_EEPROM] = "EEPROM", 18684400305SSrinivas Kandagatla [NVMEM_TYPE_OTP] = "OTP", 18784400305SSrinivas Kandagatla [NVMEM_TYPE_BATTERY_BACKED] = "Battery backed", 188fd307a4aSJiri Prchal [NVMEM_TYPE_FRAM] = "FRAM", 18984400305SSrinivas Kandagatla }; 19084400305SSrinivas Kandagatla 19184400305SSrinivas Kandagatla #ifdef CONFIG_DEBUG_LOCK_ALLOC 19284400305SSrinivas Kandagatla static struct lock_class_key eeprom_lock_key; 19384400305SSrinivas Kandagatla #endif 19484400305SSrinivas Kandagatla 19584400305SSrinivas Kandagatla static ssize_t type_show(struct device *dev, 19684400305SSrinivas Kandagatla struct device_attribute *attr, char *buf) 19784400305SSrinivas Kandagatla { 19884400305SSrinivas Kandagatla struct nvmem_device *nvmem = to_nvmem_device(dev); 19984400305SSrinivas Kandagatla 20084400305SSrinivas Kandagatla return sprintf(buf, "%s\n", nvmem_type_str[nvmem->type]); 20184400305SSrinivas Kandagatla } 20284400305SSrinivas Kandagatla 20384400305SSrinivas Kandagatla static DEVICE_ATTR_RO(type); 20484400305SSrinivas Kandagatla 20584400305SSrinivas Kandagatla static struct attribute *nvmem_attrs[] = { 20684400305SSrinivas Kandagatla &dev_attr_type.attr, 20784400305SSrinivas Kandagatla NULL, 20884400305SSrinivas Kandagatla }; 20984400305SSrinivas Kandagatla 21084400305SSrinivas Kandagatla static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj, 21184400305SSrinivas Kandagatla struct bin_attribute *attr, char *buf, 21284400305SSrinivas Kandagatla loff_t pos, size_t count) 21384400305SSrinivas Kandagatla { 21484400305SSrinivas Kandagatla struct device *dev; 21584400305SSrinivas Kandagatla struct nvmem_device *nvmem; 21684400305SSrinivas Kandagatla int rc; 21784400305SSrinivas Kandagatla 21884400305SSrinivas Kandagatla if (attr->private) 21984400305SSrinivas Kandagatla dev = attr->private; 22084400305SSrinivas Kandagatla else 22128371cc6STian Tao dev = kobj_to_dev(kobj); 22284400305SSrinivas Kandagatla nvmem = to_nvmem_device(dev); 22384400305SSrinivas Kandagatla 22484400305SSrinivas Kandagatla /* Stop the user from reading */ 22584400305SSrinivas Kandagatla if (pos >= nvmem->size) 22684400305SSrinivas Kandagatla return 0; 22784400305SSrinivas Kandagatla 22883566715SDouglas Anderson if (!IS_ALIGNED(pos, nvmem->stride)) 22983566715SDouglas Anderson return -EINVAL; 23083566715SDouglas Anderson 23184400305SSrinivas Kandagatla if (count < nvmem->word_size) 23284400305SSrinivas Kandagatla return -EINVAL; 23384400305SSrinivas Kandagatla 23484400305SSrinivas Kandagatla if (pos + count > nvmem->size) 23584400305SSrinivas Kandagatla count = nvmem->size - pos; 23684400305SSrinivas Kandagatla 23784400305SSrinivas Kandagatla count = round_down(count, nvmem->word_size); 23884400305SSrinivas Kandagatla 23984400305SSrinivas Kandagatla if (!nvmem->reg_read) 24084400305SSrinivas Kandagatla return -EPERM; 24184400305SSrinivas Kandagatla 242b96fc541SMichael Auchter rc = nvmem_reg_read(nvmem, pos, buf, count); 24384400305SSrinivas Kandagatla 24484400305SSrinivas Kandagatla if (rc) 24584400305SSrinivas Kandagatla return rc; 24684400305SSrinivas Kandagatla 24784400305SSrinivas Kandagatla return count; 24884400305SSrinivas Kandagatla } 24984400305SSrinivas Kandagatla 25084400305SSrinivas Kandagatla static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj, 25184400305SSrinivas Kandagatla struct bin_attribute *attr, char *buf, 25284400305SSrinivas Kandagatla loff_t pos, size_t count) 25384400305SSrinivas Kandagatla { 25484400305SSrinivas Kandagatla struct device *dev; 25584400305SSrinivas Kandagatla struct nvmem_device *nvmem; 25684400305SSrinivas Kandagatla int rc; 25784400305SSrinivas Kandagatla 25884400305SSrinivas Kandagatla if (attr->private) 25984400305SSrinivas Kandagatla dev = attr->private; 26084400305SSrinivas Kandagatla else 26128371cc6STian Tao dev = kobj_to_dev(kobj); 26284400305SSrinivas Kandagatla nvmem = to_nvmem_device(dev); 26384400305SSrinivas Kandagatla 26484400305SSrinivas Kandagatla /* Stop the user from writing */ 26584400305SSrinivas Kandagatla if (pos >= nvmem->size) 26684400305SSrinivas Kandagatla return -EFBIG; 26784400305SSrinivas Kandagatla 26883566715SDouglas Anderson if (!IS_ALIGNED(pos, nvmem->stride)) 26983566715SDouglas Anderson return -EINVAL; 27083566715SDouglas Anderson 27184400305SSrinivas Kandagatla if (count < nvmem->word_size) 27284400305SSrinivas Kandagatla return -EINVAL; 27384400305SSrinivas Kandagatla 27484400305SSrinivas Kandagatla if (pos + count > nvmem->size) 27584400305SSrinivas Kandagatla count = nvmem->size - pos; 27684400305SSrinivas Kandagatla 27784400305SSrinivas Kandagatla count = round_down(count, nvmem->word_size); 27884400305SSrinivas Kandagatla 27984400305SSrinivas Kandagatla if (!nvmem->reg_write) 28084400305SSrinivas Kandagatla return -EPERM; 28184400305SSrinivas Kandagatla 282b96fc541SMichael Auchter rc = nvmem_reg_write(nvmem, pos, buf, count); 28384400305SSrinivas Kandagatla 28484400305SSrinivas Kandagatla if (rc) 28584400305SSrinivas Kandagatla return rc; 28684400305SSrinivas Kandagatla 28784400305SSrinivas Kandagatla return count; 28884400305SSrinivas Kandagatla } 28984400305SSrinivas Kandagatla 2902a4542e5SSrinivas Kandagatla static umode_t nvmem_bin_attr_get_umode(struct nvmem_device *nvmem) 29184400305SSrinivas Kandagatla { 29284400305SSrinivas Kandagatla umode_t mode = 0400; 29384400305SSrinivas Kandagatla 29484400305SSrinivas Kandagatla if (!nvmem->root_only) 29584400305SSrinivas Kandagatla mode |= 0044; 29684400305SSrinivas Kandagatla 29784400305SSrinivas Kandagatla if (!nvmem->read_only) 29884400305SSrinivas Kandagatla mode |= 0200; 29984400305SSrinivas Kandagatla 30084400305SSrinivas Kandagatla if (!nvmem->reg_write) 30184400305SSrinivas Kandagatla mode &= ~0200; 30284400305SSrinivas Kandagatla 30384400305SSrinivas Kandagatla if (!nvmem->reg_read) 30484400305SSrinivas Kandagatla mode &= ~0444; 30584400305SSrinivas Kandagatla 30684400305SSrinivas Kandagatla return mode; 30784400305SSrinivas Kandagatla } 30884400305SSrinivas Kandagatla 3092a4542e5SSrinivas Kandagatla static umode_t nvmem_bin_attr_is_visible(struct kobject *kobj, 3102a4542e5SSrinivas Kandagatla struct bin_attribute *attr, int i) 3112a4542e5SSrinivas Kandagatla { 31228371cc6STian Tao struct device *dev = kobj_to_dev(kobj); 3132a4542e5SSrinivas Kandagatla struct nvmem_device *nvmem = to_nvmem_device(dev); 3142a4542e5SSrinivas Kandagatla 31586192251SSrinivas Kandagatla attr->size = nvmem->size; 31686192251SSrinivas Kandagatla 3172a4542e5SSrinivas Kandagatla return nvmem_bin_attr_get_umode(nvmem); 3182a4542e5SSrinivas Kandagatla } 3192a4542e5SSrinivas Kandagatla 32084400305SSrinivas Kandagatla /* default read/write permissions */ 32184400305SSrinivas Kandagatla static struct bin_attribute bin_attr_rw_nvmem = { 32284400305SSrinivas Kandagatla .attr = { 32384400305SSrinivas Kandagatla .name = "nvmem", 32484400305SSrinivas Kandagatla .mode = 0644, 32584400305SSrinivas Kandagatla }, 32684400305SSrinivas Kandagatla .read = bin_attr_nvmem_read, 32784400305SSrinivas Kandagatla .write = bin_attr_nvmem_write, 32884400305SSrinivas Kandagatla }; 32984400305SSrinivas Kandagatla 33084400305SSrinivas Kandagatla static struct bin_attribute *nvmem_bin_attributes[] = { 33184400305SSrinivas Kandagatla &bin_attr_rw_nvmem, 33284400305SSrinivas Kandagatla NULL, 33384400305SSrinivas Kandagatla }; 33484400305SSrinivas Kandagatla 33584400305SSrinivas Kandagatla static const struct attribute_group nvmem_bin_group = { 33684400305SSrinivas Kandagatla .bin_attrs = nvmem_bin_attributes, 33784400305SSrinivas Kandagatla .attrs = nvmem_attrs, 33884400305SSrinivas Kandagatla .is_bin_visible = nvmem_bin_attr_is_visible, 33984400305SSrinivas Kandagatla }; 34084400305SSrinivas Kandagatla 34184400305SSrinivas Kandagatla static const struct attribute_group *nvmem_dev_groups[] = { 34284400305SSrinivas Kandagatla &nvmem_bin_group, 34384400305SSrinivas Kandagatla NULL, 34484400305SSrinivas Kandagatla }; 34584400305SSrinivas Kandagatla 3462a4542e5SSrinivas Kandagatla static struct bin_attribute bin_attr_nvmem_eeprom_compat = { 34784400305SSrinivas Kandagatla .attr = { 3482a4542e5SSrinivas Kandagatla .name = "eeprom", 34984400305SSrinivas Kandagatla }, 35084400305SSrinivas Kandagatla .read = bin_attr_nvmem_read, 35184400305SSrinivas Kandagatla .write = bin_attr_nvmem_write, 35284400305SSrinivas Kandagatla }; 35384400305SSrinivas Kandagatla 35484400305SSrinivas Kandagatla /* 35584400305SSrinivas Kandagatla * nvmem_setup_compat() - Create an additional binary entry in 35684400305SSrinivas Kandagatla * drivers sys directory, to be backwards compatible with the older 35784400305SSrinivas Kandagatla * drivers/misc/eeprom drivers. 35884400305SSrinivas Kandagatla */ 35984400305SSrinivas Kandagatla static int nvmem_sysfs_setup_compat(struct nvmem_device *nvmem, 36084400305SSrinivas Kandagatla const struct nvmem_config *config) 36184400305SSrinivas Kandagatla { 36284400305SSrinivas Kandagatla int rval; 36384400305SSrinivas Kandagatla 36484400305SSrinivas Kandagatla if (!config->compat) 36584400305SSrinivas Kandagatla return 0; 36684400305SSrinivas Kandagatla 36784400305SSrinivas Kandagatla if (!config->base_dev) 36884400305SSrinivas Kandagatla return -EINVAL; 36984400305SSrinivas Kandagatla 370fd307a4aSJiri Prchal if (config->type == NVMEM_TYPE_FRAM) 371fd307a4aSJiri Prchal bin_attr_nvmem_eeprom_compat.attr.name = "fram"; 372fd307a4aSJiri Prchal 3732a4542e5SSrinivas Kandagatla nvmem->eeprom = bin_attr_nvmem_eeprom_compat; 3742a4542e5SSrinivas Kandagatla nvmem->eeprom.attr.mode = nvmem_bin_attr_get_umode(nvmem); 37584400305SSrinivas Kandagatla nvmem->eeprom.size = nvmem->size; 37684400305SSrinivas Kandagatla #ifdef CONFIG_DEBUG_LOCK_ALLOC 37784400305SSrinivas Kandagatla nvmem->eeprom.attr.key = &eeprom_lock_key; 37884400305SSrinivas Kandagatla #endif 37984400305SSrinivas Kandagatla nvmem->eeprom.private = &nvmem->dev; 38084400305SSrinivas Kandagatla nvmem->base_dev = config->base_dev; 38184400305SSrinivas Kandagatla 38284400305SSrinivas Kandagatla rval = device_create_bin_file(nvmem->base_dev, &nvmem->eeprom); 38384400305SSrinivas Kandagatla if (rval) { 38484400305SSrinivas Kandagatla dev_err(&nvmem->dev, 38584400305SSrinivas Kandagatla "Failed to create eeprom binary file %d\n", rval); 38684400305SSrinivas Kandagatla return rval; 38784400305SSrinivas Kandagatla } 38884400305SSrinivas Kandagatla 38984400305SSrinivas Kandagatla nvmem->flags |= FLAG_COMPAT; 39084400305SSrinivas Kandagatla 39184400305SSrinivas Kandagatla return 0; 39284400305SSrinivas Kandagatla } 39384400305SSrinivas Kandagatla 39484400305SSrinivas Kandagatla static void nvmem_sysfs_remove_compat(struct nvmem_device *nvmem, 39584400305SSrinivas Kandagatla const struct nvmem_config *config) 39684400305SSrinivas Kandagatla { 39784400305SSrinivas Kandagatla if (config->compat) 39884400305SSrinivas Kandagatla device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); 39984400305SSrinivas Kandagatla } 40084400305SSrinivas Kandagatla 40184400305SSrinivas Kandagatla #else /* CONFIG_NVMEM_SYSFS */ 40284400305SSrinivas Kandagatla 40384400305SSrinivas Kandagatla static int nvmem_sysfs_setup_compat(struct nvmem_device *nvmem, 40484400305SSrinivas Kandagatla const struct nvmem_config *config) 40584400305SSrinivas Kandagatla { 40684400305SSrinivas Kandagatla return -ENOSYS; 40784400305SSrinivas Kandagatla } 40884400305SSrinivas Kandagatla static void nvmem_sysfs_remove_compat(struct nvmem_device *nvmem, 40984400305SSrinivas Kandagatla const struct nvmem_config *config) 41084400305SSrinivas Kandagatla { 41184400305SSrinivas Kandagatla } 41284400305SSrinivas Kandagatla 41384400305SSrinivas Kandagatla #endif /* CONFIG_NVMEM_SYSFS */ 414a8b44d5dSAndy Shevchenko 415eace75cfSSrinivas Kandagatla static void nvmem_release(struct device *dev) 416eace75cfSSrinivas Kandagatla { 417eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem = to_nvmem_device(dev); 418eace75cfSSrinivas Kandagatla 4191eb51d6aSBartosz Golaszewski ida_free(&nvmem_ida, nvmem->id); 420a9c3766cSKhouloud Touil gpiod_put(nvmem->wp_gpio); 421eace75cfSSrinivas Kandagatla kfree(nvmem); 422eace75cfSSrinivas Kandagatla } 423eace75cfSSrinivas Kandagatla 424eace75cfSSrinivas Kandagatla static const struct device_type nvmem_provider_type = { 425eace75cfSSrinivas Kandagatla .release = nvmem_release, 426eace75cfSSrinivas Kandagatla }; 427eace75cfSSrinivas Kandagatla 428eace75cfSSrinivas Kandagatla static struct bus_type nvmem_bus_type = { 429eace75cfSSrinivas Kandagatla .name = "nvmem", 430eace75cfSSrinivas Kandagatla }; 431eace75cfSSrinivas Kandagatla 4327ae6478bSSrinivas Kandagatla static void nvmem_cell_entry_drop(struct nvmem_cell_entry *cell) 433eace75cfSSrinivas Kandagatla { 434bee1138bSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_REMOVE, cell); 435c7235ee3SBartosz Golaszewski mutex_lock(&nvmem_mutex); 436eace75cfSSrinivas Kandagatla list_del(&cell->node); 437c7235ee3SBartosz Golaszewski mutex_unlock(&nvmem_mutex); 4380749aa25SSrinivas Kandagatla of_node_put(cell->np); 43916bb7abcSBitan Biswas kfree_const(cell->name); 440eace75cfSSrinivas Kandagatla kfree(cell); 441eace75cfSSrinivas Kandagatla } 442eace75cfSSrinivas Kandagatla 443eace75cfSSrinivas Kandagatla static void nvmem_device_remove_all_cells(const struct nvmem_device *nvmem) 444eace75cfSSrinivas Kandagatla { 4457ae6478bSSrinivas Kandagatla struct nvmem_cell_entry *cell, *p; 446eace75cfSSrinivas Kandagatla 447c7235ee3SBartosz Golaszewski list_for_each_entry_safe(cell, p, &nvmem->cells, node) 4487ae6478bSSrinivas Kandagatla nvmem_cell_entry_drop(cell); 449eace75cfSSrinivas Kandagatla } 450eace75cfSSrinivas Kandagatla 4517ae6478bSSrinivas Kandagatla static void nvmem_cell_entry_add(struct nvmem_cell_entry *cell) 452eace75cfSSrinivas Kandagatla { 453c7235ee3SBartosz Golaszewski mutex_lock(&nvmem_mutex); 454c7235ee3SBartosz Golaszewski list_add_tail(&cell->node, &cell->nvmem->cells); 455c7235ee3SBartosz Golaszewski mutex_unlock(&nvmem_mutex); 456bee1138bSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_ADD, cell); 457eace75cfSSrinivas Kandagatla } 458eace75cfSSrinivas Kandagatla 4597ae6478bSSrinivas Kandagatla static int nvmem_cell_info_to_nvmem_cell_entry_nodup(struct nvmem_device *nvmem, 460eace75cfSSrinivas Kandagatla const struct nvmem_cell_info *info, 4617ae6478bSSrinivas Kandagatla struct nvmem_cell_entry *cell) 462eace75cfSSrinivas Kandagatla { 463eace75cfSSrinivas Kandagatla cell->nvmem = nvmem; 464eace75cfSSrinivas Kandagatla cell->offset = info->offset; 465eace75cfSSrinivas Kandagatla cell->bytes = info->bytes; 466fc9eec4dSVadym Kochan cell->name = info->name; 467eace75cfSSrinivas Kandagatla 468eace75cfSSrinivas Kandagatla cell->bit_offset = info->bit_offset; 469eace75cfSSrinivas Kandagatla cell->nbits = info->nbits; 470dbc2f620SRafał Miłecki cell->np = info->np; 471eace75cfSSrinivas Kandagatla 472eace75cfSSrinivas Kandagatla if (cell->nbits) 473eace75cfSSrinivas Kandagatla cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset, 474eace75cfSSrinivas Kandagatla BITS_PER_BYTE); 475eace75cfSSrinivas Kandagatla 476eace75cfSSrinivas Kandagatla if (!IS_ALIGNED(cell->offset, nvmem->stride)) { 477eace75cfSSrinivas Kandagatla dev_err(&nvmem->dev, 478eace75cfSSrinivas Kandagatla "cell %s unaligned to nvmem stride %d\n", 479fc9eec4dSVadym Kochan cell->name ?: "<unknown>", nvmem->stride); 480eace75cfSSrinivas Kandagatla return -EINVAL; 481eace75cfSSrinivas Kandagatla } 482eace75cfSSrinivas Kandagatla 483eace75cfSSrinivas Kandagatla return 0; 484eace75cfSSrinivas Kandagatla } 485eace75cfSSrinivas Kandagatla 4867ae6478bSSrinivas Kandagatla static int nvmem_cell_info_to_nvmem_cell_entry(struct nvmem_device *nvmem, 487fc9eec4dSVadym Kochan const struct nvmem_cell_info *info, 4887ae6478bSSrinivas Kandagatla struct nvmem_cell_entry *cell) 489fc9eec4dSVadym Kochan { 490fc9eec4dSVadym Kochan int err; 491fc9eec4dSVadym Kochan 4927ae6478bSSrinivas Kandagatla err = nvmem_cell_info_to_nvmem_cell_entry_nodup(nvmem, info, cell); 493fc9eec4dSVadym Kochan if (err) 494fc9eec4dSVadym Kochan return err; 495fc9eec4dSVadym Kochan 496fc9eec4dSVadym Kochan cell->name = kstrdup_const(info->name, GFP_KERNEL); 497fc9eec4dSVadym Kochan if (!cell->name) 498fc9eec4dSVadym Kochan return -ENOMEM; 499fc9eec4dSVadym Kochan 500fc9eec4dSVadym Kochan return 0; 501fc9eec4dSVadym Kochan } 502fc9eec4dSVadym Kochan 503b3db17e4SAndrew Lunn /** 504b3db17e4SAndrew Lunn * nvmem_add_cells() - Add cell information to an nvmem device 505b3db17e4SAndrew Lunn * 506b3db17e4SAndrew Lunn * @nvmem: nvmem device to add cells to. 507b3db17e4SAndrew Lunn * @info: nvmem cell info to add to the device 508b3db17e4SAndrew Lunn * @ncells: number of cells in info 509b3db17e4SAndrew Lunn * 510b3db17e4SAndrew Lunn * Return: 0 or negative error code on failure. 511b3db17e4SAndrew Lunn */ 512ef92ab30SSrinivas Kandagatla static int nvmem_add_cells(struct nvmem_device *nvmem, 513b3db17e4SAndrew Lunn const struct nvmem_cell_info *info, 514b3db17e4SAndrew Lunn int ncells) 515eace75cfSSrinivas Kandagatla { 5167ae6478bSSrinivas Kandagatla struct nvmem_cell_entry **cells; 517eace75cfSSrinivas Kandagatla int i, rval; 518eace75cfSSrinivas Kandagatla 519b3db17e4SAndrew Lunn cells = kcalloc(ncells, sizeof(*cells), GFP_KERNEL); 520eace75cfSSrinivas Kandagatla if (!cells) 521eace75cfSSrinivas Kandagatla return -ENOMEM; 522eace75cfSSrinivas Kandagatla 523b3db17e4SAndrew Lunn for (i = 0; i < ncells; i++) { 524eace75cfSSrinivas Kandagatla cells[i] = kzalloc(sizeof(**cells), GFP_KERNEL); 525eace75cfSSrinivas Kandagatla if (!cells[i]) { 526eace75cfSSrinivas Kandagatla rval = -ENOMEM; 527eace75cfSSrinivas Kandagatla goto err; 528eace75cfSSrinivas Kandagatla } 529eace75cfSSrinivas Kandagatla 5307ae6478bSSrinivas Kandagatla rval = nvmem_cell_info_to_nvmem_cell_entry(nvmem, &info[i], cells[i]); 531287980e4SArnd Bergmann if (rval) { 532eace75cfSSrinivas Kandagatla kfree(cells[i]); 533eace75cfSSrinivas Kandagatla goto err; 534eace75cfSSrinivas Kandagatla } 535eace75cfSSrinivas Kandagatla 5367ae6478bSSrinivas Kandagatla nvmem_cell_entry_add(cells[i]); 537eace75cfSSrinivas Kandagatla } 538eace75cfSSrinivas Kandagatla 539eace75cfSSrinivas Kandagatla /* remove tmp array */ 540eace75cfSSrinivas Kandagatla kfree(cells); 541eace75cfSSrinivas Kandagatla 542eace75cfSSrinivas Kandagatla return 0; 543eace75cfSSrinivas Kandagatla err: 544dfdf1414SRasmus Villemoes while (i--) 5457ae6478bSSrinivas Kandagatla nvmem_cell_entry_drop(cells[i]); 546eace75cfSSrinivas Kandagatla 547dfdf1414SRasmus Villemoes kfree(cells); 548dfdf1414SRasmus Villemoes 549eace75cfSSrinivas Kandagatla return rval; 550eace75cfSSrinivas Kandagatla } 551eace75cfSSrinivas Kandagatla 552bee1138bSBartosz Golaszewski /** 553bee1138bSBartosz Golaszewski * nvmem_register_notifier() - Register a notifier block for nvmem events. 554bee1138bSBartosz Golaszewski * 555bee1138bSBartosz Golaszewski * @nb: notifier block to be called on nvmem events. 556bee1138bSBartosz Golaszewski * 557bee1138bSBartosz Golaszewski * Return: 0 on success, negative error number on failure. 558bee1138bSBartosz Golaszewski */ 559bee1138bSBartosz Golaszewski int nvmem_register_notifier(struct notifier_block *nb) 560bee1138bSBartosz Golaszewski { 561bee1138bSBartosz Golaszewski return blocking_notifier_chain_register(&nvmem_notifier, nb); 562bee1138bSBartosz Golaszewski } 563bee1138bSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_register_notifier); 564bee1138bSBartosz Golaszewski 565bee1138bSBartosz Golaszewski /** 566bee1138bSBartosz Golaszewski * nvmem_unregister_notifier() - Unregister a notifier block for nvmem events. 567bee1138bSBartosz Golaszewski * 568bee1138bSBartosz Golaszewski * @nb: notifier block to be unregistered. 569bee1138bSBartosz Golaszewski * 570bee1138bSBartosz Golaszewski * Return: 0 on success, negative error number on failure. 571bee1138bSBartosz Golaszewski */ 572bee1138bSBartosz Golaszewski int nvmem_unregister_notifier(struct notifier_block *nb) 573bee1138bSBartosz Golaszewski { 574bee1138bSBartosz Golaszewski return blocking_notifier_chain_unregister(&nvmem_notifier, nb); 575bee1138bSBartosz Golaszewski } 576bee1138bSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_unregister_notifier); 577bee1138bSBartosz Golaszewski 578b985f4cbSBartosz Golaszewski static int nvmem_add_cells_from_table(struct nvmem_device *nvmem) 579b985f4cbSBartosz Golaszewski { 580b985f4cbSBartosz Golaszewski const struct nvmem_cell_info *info; 581b985f4cbSBartosz Golaszewski struct nvmem_cell_table *table; 5827ae6478bSSrinivas Kandagatla struct nvmem_cell_entry *cell; 583b985f4cbSBartosz Golaszewski int rval = 0, i; 584b985f4cbSBartosz Golaszewski 585b985f4cbSBartosz Golaszewski mutex_lock(&nvmem_cell_mutex); 586b985f4cbSBartosz Golaszewski list_for_each_entry(table, &nvmem_cell_tables, node) { 587b985f4cbSBartosz Golaszewski if (strcmp(nvmem_dev_name(nvmem), table->nvmem_name) == 0) { 588b985f4cbSBartosz Golaszewski for (i = 0; i < table->ncells; i++) { 589b985f4cbSBartosz Golaszewski info = &table->cells[i]; 590b985f4cbSBartosz Golaszewski 591b985f4cbSBartosz Golaszewski cell = kzalloc(sizeof(*cell), GFP_KERNEL); 592b985f4cbSBartosz Golaszewski if (!cell) { 593b985f4cbSBartosz Golaszewski rval = -ENOMEM; 594b985f4cbSBartosz Golaszewski goto out; 595b985f4cbSBartosz Golaszewski } 596b985f4cbSBartosz Golaszewski 5977ae6478bSSrinivas Kandagatla rval = nvmem_cell_info_to_nvmem_cell_entry(nvmem, info, cell); 598b985f4cbSBartosz Golaszewski if (rval) { 599b985f4cbSBartosz Golaszewski kfree(cell); 600b985f4cbSBartosz Golaszewski goto out; 601b985f4cbSBartosz Golaszewski } 602b985f4cbSBartosz Golaszewski 6037ae6478bSSrinivas Kandagatla nvmem_cell_entry_add(cell); 604b985f4cbSBartosz Golaszewski } 605b985f4cbSBartosz Golaszewski } 606b985f4cbSBartosz Golaszewski } 607b985f4cbSBartosz Golaszewski 608b985f4cbSBartosz Golaszewski out: 609b985f4cbSBartosz Golaszewski mutex_unlock(&nvmem_cell_mutex); 610b985f4cbSBartosz Golaszewski return rval; 611b985f4cbSBartosz Golaszewski } 612b985f4cbSBartosz Golaszewski 6137ae6478bSSrinivas Kandagatla static struct nvmem_cell_entry * 6147ae6478bSSrinivas Kandagatla nvmem_find_cell_entry_by_name(struct nvmem_device *nvmem, const char *cell_id) 615506157beSBartosz Golaszewski { 6167ae6478bSSrinivas Kandagatla struct nvmem_cell_entry *iter, *cell = NULL; 617506157beSBartosz Golaszewski 618506157beSBartosz Golaszewski mutex_lock(&nvmem_mutex); 6191c832674SAlban Bedel list_for_each_entry(iter, &nvmem->cells, node) { 6201c832674SAlban Bedel if (strcmp(cell_id, iter->name) == 0) { 6211c832674SAlban Bedel cell = iter; 622506157beSBartosz Golaszewski break; 623506157beSBartosz Golaszewski } 6241c832674SAlban Bedel } 625506157beSBartosz Golaszewski mutex_unlock(&nvmem_mutex); 626506157beSBartosz Golaszewski 627506157beSBartosz Golaszewski return cell; 628506157beSBartosz Golaszewski } 629506157beSBartosz Golaszewski 630fd3bb8f5SEvan Green static int nvmem_validate_keepouts(struct nvmem_device *nvmem) 631fd3bb8f5SEvan Green { 632fd3bb8f5SEvan Green unsigned int cur = 0; 633fd3bb8f5SEvan Green const struct nvmem_keepout *keepout = nvmem->keepout; 634fd3bb8f5SEvan Green const struct nvmem_keepout *keepoutend = keepout + nvmem->nkeepout; 635fd3bb8f5SEvan Green 636fd3bb8f5SEvan Green while (keepout < keepoutend) { 637fd3bb8f5SEvan Green /* Ensure keepouts are sorted and don't overlap. */ 638fd3bb8f5SEvan Green if (keepout->start < cur) { 639fd3bb8f5SEvan Green dev_err(&nvmem->dev, 640fd3bb8f5SEvan Green "Keepout regions aren't sorted or overlap.\n"); 641fd3bb8f5SEvan Green 642fd3bb8f5SEvan Green return -ERANGE; 643fd3bb8f5SEvan Green } 644fd3bb8f5SEvan Green 645fd3bb8f5SEvan Green if (keepout->end < keepout->start) { 646fd3bb8f5SEvan Green dev_err(&nvmem->dev, 647fd3bb8f5SEvan Green "Invalid keepout region.\n"); 648fd3bb8f5SEvan Green 649fd3bb8f5SEvan Green return -EINVAL; 650fd3bb8f5SEvan Green } 651fd3bb8f5SEvan Green 652fd3bb8f5SEvan Green /* 653fd3bb8f5SEvan Green * Validate keepouts (and holes between) don't violate 654fd3bb8f5SEvan Green * word_size constraints. 655fd3bb8f5SEvan Green */ 656fd3bb8f5SEvan Green if ((keepout->end - keepout->start < nvmem->word_size) || 657fd3bb8f5SEvan Green ((keepout->start != cur) && 658fd3bb8f5SEvan Green (keepout->start - cur < nvmem->word_size))) { 659fd3bb8f5SEvan Green 660fd3bb8f5SEvan Green dev_err(&nvmem->dev, 661fd3bb8f5SEvan Green "Keepout regions violate word_size constraints.\n"); 662fd3bb8f5SEvan Green 663fd3bb8f5SEvan Green return -ERANGE; 664fd3bb8f5SEvan Green } 665fd3bb8f5SEvan Green 666fd3bb8f5SEvan Green /* Validate keepouts don't violate stride (alignment). */ 667fd3bb8f5SEvan Green if (!IS_ALIGNED(keepout->start, nvmem->stride) || 668fd3bb8f5SEvan Green !IS_ALIGNED(keepout->end, nvmem->stride)) { 669fd3bb8f5SEvan Green 670fd3bb8f5SEvan Green dev_err(&nvmem->dev, 671fd3bb8f5SEvan Green "Keepout regions violate stride.\n"); 672fd3bb8f5SEvan Green 673fd3bb8f5SEvan Green return -EINVAL; 674fd3bb8f5SEvan Green } 675fd3bb8f5SEvan Green 676fd3bb8f5SEvan Green cur = keepout->end; 677fd3bb8f5SEvan Green keepout++; 678fd3bb8f5SEvan Green } 679fd3bb8f5SEvan Green 680fd3bb8f5SEvan Green return 0; 681fd3bb8f5SEvan Green } 682fd3bb8f5SEvan Green 683e888d445SBartosz Golaszewski static int nvmem_add_cells_from_of(struct nvmem_device *nvmem) 684e888d445SBartosz Golaszewski { 685e888d445SBartosz Golaszewski struct device_node *parent, *child; 686e888d445SBartosz Golaszewski struct device *dev = &nvmem->dev; 6877ae6478bSSrinivas Kandagatla struct nvmem_cell_entry *cell; 688e888d445SBartosz Golaszewski const __be32 *addr; 689e888d445SBartosz Golaszewski int len; 690e888d445SBartosz Golaszewski 691e888d445SBartosz Golaszewski parent = dev->of_node; 692e888d445SBartosz Golaszewski 693e888d445SBartosz Golaszewski for_each_child_of_node(parent, child) { 694e888d445SBartosz Golaszewski addr = of_get_property(child, "reg", &len); 6950445efacSAhmad Fatoum if (!addr) 6960445efacSAhmad Fatoum continue; 6970445efacSAhmad Fatoum if (len < 2 * sizeof(u32)) { 698e888d445SBartosz Golaszewski dev_err(dev, "nvmem: invalid reg on %pOF\n", child); 69963879e29SChristophe JAILLET of_node_put(child); 700e888d445SBartosz Golaszewski return -EINVAL; 701e888d445SBartosz Golaszewski } 702e888d445SBartosz Golaszewski 703e888d445SBartosz Golaszewski cell = kzalloc(sizeof(*cell), GFP_KERNEL); 70463879e29SChristophe JAILLET if (!cell) { 70563879e29SChristophe JAILLET of_node_put(child); 706e888d445SBartosz Golaszewski return -ENOMEM; 70763879e29SChristophe JAILLET } 708e888d445SBartosz Golaszewski 709e888d445SBartosz Golaszewski cell->nvmem = nvmem; 710e888d445SBartosz Golaszewski cell->offset = be32_to_cpup(addr++); 711e888d445SBartosz Golaszewski cell->bytes = be32_to_cpup(addr); 712badcdff1SRob Herring cell->name = kasprintf(GFP_KERNEL, "%pOFn", child); 713e888d445SBartosz Golaszewski 714e888d445SBartosz Golaszewski addr = of_get_property(child, "bits", &len); 715e888d445SBartosz Golaszewski if (addr && len == (2 * sizeof(u32))) { 716e888d445SBartosz Golaszewski cell->bit_offset = be32_to_cpup(addr++); 717e888d445SBartosz Golaszewski cell->nbits = be32_to_cpup(addr); 718e888d445SBartosz Golaszewski } 719e888d445SBartosz Golaszewski 720e888d445SBartosz Golaszewski if (cell->nbits) 721e888d445SBartosz Golaszewski cell->bytes = DIV_ROUND_UP( 722e888d445SBartosz Golaszewski cell->nbits + cell->bit_offset, 723e888d445SBartosz Golaszewski BITS_PER_BYTE); 724e888d445SBartosz Golaszewski 725e888d445SBartosz Golaszewski if (!IS_ALIGNED(cell->offset, nvmem->stride)) { 726e888d445SBartosz Golaszewski dev_err(dev, "cell %s unaligned to nvmem stride %d\n", 727e888d445SBartosz Golaszewski cell->name, nvmem->stride); 728e888d445SBartosz Golaszewski /* Cells already added will be freed later. */ 72916bb7abcSBitan Biswas kfree_const(cell->name); 730e888d445SBartosz Golaszewski kfree(cell); 73163879e29SChristophe JAILLET of_node_put(child); 732e888d445SBartosz Golaszewski return -EINVAL; 733e888d445SBartosz Golaszewski } 734e888d445SBartosz Golaszewski 73563879e29SChristophe JAILLET cell->np = of_node_get(child); 7367ae6478bSSrinivas Kandagatla nvmem_cell_entry_add(cell); 737e888d445SBartosz Golaszewski } 738e888d445SBartosz Golaszewski 739e888d445SBartosz Golaszewski return 0; 740e888d445SBartosz Golaszewski } 741e888d445SBartosz Golaszewski 742eace75cfSSrinivas Kandagatla /** 743eace75cfSSrinivas Kandagatla * nvmem_register() - Register a nvmem device for given nvmem_config. 7443a758071SAndreas Färber * Also creates a binary entry in /sys/bus/nvmem/devices/dev-name/nvmem 745eace75cfSSrinivas Kandagatla * 746eace75cfSSrinivas Kandagatla * @config: nvmem device configuration with which nvmem device is created. 747eace75cfSSrinivas Kandagatla * 748eace75cfSSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device 749eace75cfSSrinivas Kandagatla * on success. 750eace75cfSSrinivas Kandagatla */ 751eace75cfSSrinivas Kandagatla 752eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem_register(const struct nvmem_config *config) 753eace75cfSSrinivas Kandagatla { 754eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem; 755eace75cfSSrinivas Kandagatla int rval; 756eace75cfSSrinivas Kandagatla 757eace75cfSSrinivas Kandagatla if (!config->dev) 758eace75cfSSrinivas Kandagatla return ERR_PTR(-EINVAL); 759eace75cfSSrinivas Kandagatla 760061a320bSSrinivas Kandagatla if (!config->reg_read && !config->reg_write) 761061a320bSSrinivas Kandagatla return ERR_PTR(-EINVAL); 762061a320bSSrinivas Kandagatla 763eace75cfSSrinivas Kandagatla nvmem = kzalloc(sizeof(*nvmem), GFP_KERNEL); 764eace75cfSSrinivas Kandagatla if (!nvmem) 765eace75cfSSrinivas Kandagatla return ERR_PTR(-ENOMEM); 766eace75cfSSrinivas Kandagatla 7671eb51d6aSBartosz Golaszewski rval = ida_alloc(&nvmem_ida, GFP_KERNEL); 768eace75cfSSrinivas Kandagatla if (rval < 0) { 769eace75cfSSrinivas Kandagatla kfree(nvmem); 770eace75cfSSrinivas Kandagatla return ERR_PTR(rval); 771eace75cfSSrinivas Kandagatla } 77231c6ff51SBartosz Golaszewski 7733bd747c7SRussell King (Oracle) nvmem->id = rval; 7743bd747c7SRussell King (Oracle) 775560181d3SRussell King (Oracle) nvmem->dev.type = &nvmem_provider_type; 776560181d3SRussell King (Oracle) nvmem->dev.bus = &nvmem_bus_type; 777560181d3SRussell King (Oracle) nvmem->dev.parent = config->dev; 778560181d3SRussell King (Oracle) 779560181d3SRussell King (Oracle) device_initialize(&nvmem->dev); 780560181d3SRussell King (Oracle) 781569653f0SRussell King (Oracle) if (!config->ignore_wp) 7822a127da4SKhouloud Touil nvmem->wp_gpio = gpiod_get_optional(config->dev, "wp", 7832a127da4SKhouloud Touil GPIOD_OUT_HIGH); 784f7d8d7dcSBartosz Golaszewski if (IS_ERR(nvmem->wp_gpio)) { 785f7d8d7dcSBartosz Golaszewski rval = PTR_ERR(nvmem->wp_gpio); 786560181d3SRussell King (Oracle) goto err_put_device; 787f7d8d7dcSBartosz Golaszewski } 7882a127da4SKhouloud Touil 789c1de7f43SBartosz Golaszewski kref_init(&nvmem->refcnt); 790c7235ee3SBartosz Golaszewski INIT_LIST_HEAD(&nvmem->cells); 791c1de7f43SBartosz Golaszewski 792eace75cfSSrinivas Kandagatla nvmem->owner = config->owner; 79317eb18d6SMasahiro Yamada if (!nvmem->owner && config->dev->driver) 79417eb18d6SMasahiro Yamada nvmem->owner = config->dev->driver->owner; 79599897efdSHeiner Kallweit nvmem->stride = config->stride ?: 1; 79699897efdSHeiner Kallweit nvmem->word_size = config->word_size ?: 1; 797795ddd18SSrinivas Kandagatla nvmem->size = config->size; 798e6de179dSSrinivas Kandagatla nvmem->root_only = config->root_only; 799795ddd18SSrinivas Kandagatla nvmem->priv = config->priv; 80016688453SAlexandre Belloni nvmem->type = config->type; 801795ddd18SSrinivas Kandagatla nvmem->reg_read = config->reg_read; 802795ddd18SSrinivas Kandagatla nvmem->reg_write = config->reg_write; 8035008062fSSrinivas Kandagatla nvmem->cell_post_process = config->cell_post_process; 804fd3bb8f5SEvan Green nvmem->keepout = config->keepout; 805fd3bb8f5SEvan Green nvmem->nkeepout = config->nkeepout; 8061333a677SMichael Walle if (config->of_node) 8071333a677SMichael Walle nvmem->dev.of_node = config->of_node; 8081333a677SMichael Walle else if (!config->no_of_node) 809fc2f9970SHeiner Kallweit nvmem->dev.of_node = config->dev->of_node; 810fd0f4906SAndrey Smirnov 811731aa3faSSrinivas Kandagatla switch (config->id) { 812731aa3faSSrinivas Kandagatla case NVMEM_DEVID_NONE: 8135544e90cSGaosheng Cui rval = dev_set_name(&nvmem->dev, "%s", config->name); 814731aa3faSSrinivas Kandagatla break; 815731aa3faSSrinivas Kandagatla case NVMEM_DEVID_AUTO: 8165544e90cSGaosheng Cui rval = dev_set_name(&nvmem->dev, "%s%d", config->name, nvmem->id); 817731aa3faSSrinivas Kandagatla break; 818731aa3faSSrinivas Kandagatla default: 8195544e90cSGaosheng Cui rval = dev_set_name(&nvmem->dev, "%s%d", 8205253193dSAban Bedel config->name ? : "nvmem", 8215253193dSAban Bedel config->name ? config->id : nvmem->id); 822731aa3faSSrinivas Kandagatla break; 823fd0f4906SAndrey Smirnov } 824eace75cfSSrinivas Kandagatla 825560181d3SRussell King (Oracle) if (rval) 826560181d3SRussell King (Oracle) goto err_put_device; 8275544e90cSGaosheng Cui 8281716cfe8SAlban Bedel nvmem->read_only = device_property_present(config->dev, "read-only") || 8291716cfe8SAlban Bedel config->read_only || !nvmem->reg_write; 830eace75cfSSrinivas Kandagatla 83184400305SSrinivas Kandagatla #ifdef CONFIG_NVMEM_SYSFS 83284400305SSrinivas Kandagatla nvmem->dev.groups = nvmem_dev_groups; 83384400305SSrinivas Kandagatla #endif 834eace75cfSSrinivas Kandagatla 835bd124456SGaosheng Cui if (nvmem->nkeepout) { 836bd124456SGaosheng Cui rval = nvmem_validate_keepouts(nvmem); 837bd124456SGaosheng Cui if (rval) 838ab3428cfSRussell King (Oracle) goto err_put_device; 839bd124456SGaosheng Cui } 840bd124456SGaosheng Cui 841b6c217abSAndrew Lunn if (config->compat) { 842ae0c2d72SSrinivas Kandagatla rval = nvmem_sysfs_setup_compat(nvmem, config); 843b6c217abSAndrew Lunn if (rval) 844ab3428cfSRussell King (Oracle) goto err_put_device; 845eace75cfSSrinivas Kandagatla } 846eace75cfSSrinivas Kandagatla 847fa72d847SBartosz Golaszewski if (config->cells) { 848fa72d847SBartosz Golaszewski rval = nvmem_add_cells(nvmem, config->cells, config->ncells); 849fa72d847SBartosz Golaszewski if (rval) 850fa72d847SBartosz Golaszewski goto err_teardown_compat; 851fa72d847SBartosz Golaszewski } 852eace75cfSSrinivas Kandagatla 853b985f4cbSBartosz Golaszewski rval = nvmem_add_cells_from_table(nvmem); 854b985f4cbSBartosz Golaszewski if (rval) 855b985f4cbSBartosz Golaszewski goto err_remove_cells; 856b985f4cbSBartosz Golaszewski 857e888d445SBartosz Golaszewski rval = nvmem_add_cells_from_of(nvmem); 858e888d445SBartosz Golaszewski if (rval) 859e888d445SBartosz Golaszewski goto err_remove_cells; 860e888d445SBartosz Golaszewski 861ab3428cfSRussell King (Oracle) dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name); 862ab3428cfSRussell King (Oracle) 863ab3428cfSRussell King (Oracle) rval = device_add(&nvmem->dev); 864ab3428cfSRussell King (Oracle) if (rval) 865ab3428cfSRussell King (Oracle) goto err_remove_cells; 866ab3428cfSRussell King (Oracle) 867f4853e1cSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_ADD, nvmem); 868bee1138bSBartosz Golaszewski 869eace75cfSSrinivas Kandagatla return nvmem; 8703360acdfSJohan Hovold 871b985f4cbSBartosz Golaszewski err_remove_cells: 872b985f4cbSBartosz Golaszewski nvmem_device_remove_all_cells(nvmem); 873fa72d847SBartosz Golaszewski err_teardown_compat: 874fa72d847SBartosz Golaszewski if (config->compat) 875ae0c2d72SSrinivas Kandagatla nvmem_sysfs_remove_compat(nvmem, config); 8763360acdfSJohan Hovold err_put_device: 8773360acdfSJohan Hovold put_device(&nvmem->dev); 8783360acdfSJohan Hovold 879b6c217abSAndrew Lunn return ERR_PTR(rval); 880eace75cfSSrinivas Kandagatla } 881eace75cfSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_register); 882eace75cfSSrinivas Kandagatla 883c1de7f43SBartosz Golaszewski static void nvmem_device_release(struct kref *kref) 884c1de7f43SBartosz Golaszewski { 885c1de7f43SBartosz Golaszewski struct nvmem_device *nvmem; 886c1de7f43SBartosz Golaszewski 887c1de7f43SBartosz Golaszewski nvmem = container_of(kref, struct nvmem_device, refcnt); 888c1de7f43SBartosz Golaszewski 889bee1138bSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_REMOVE, nvmem); 890bee1138bSBartosz Golaszewski 891c1de7f43SBartosz Golaszewski if (nvmem->flags & FLAG_COMPAT) 892c1de7f43SBartosz Golaszewski device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); 893c1de7f43SBartosz Golaszewski 894c1de7f43SBartosz Golaszewski nvmem_device_remove_all_cells(nvmem); 895f60442ddSSrinivas Kandagatla device_unregister(&nvmem->dev); 896c1de7f43SBartosz Golaszewski } 897c1de7f43SBartosz Golaszewski 898eace75cfSSrinivas Kandagatla /** 899eace75cfSSrinivas Kandagatla * nvmem_unregister() - Unregister previously registered nvmem device 900eace75cfSSrinivas Kandagatla * 901eace75cfSSrinivas Kandagatla * @nvmem: Pointer to previously registered nvmem device. 902eace75cfSSrinivas Kandagatla */ 903bf58e882SBartosz Golaszewski void nvmem_unregister(struct nvmem_device *nvmem) 904eace75cfSSrinivas Kandagatla { 9058c751e0dSAndy Shevchenko if (nvmem) 906c1de7f43SBartosz Golaszewski kref_put(&nvmem->refcnt, nvmem_device_release); 907eace75cfSSrinivas Kandagatla } 908eace75cfSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_unregister); 909eace75cfSSrinivas Kandagatla 9105825b2c6SAndy Shevchenko static void devm_nvmem_unregister(void *nvmem) 911f1f50ecaSAndrey Smirnov { 9125825b2c6SAndy Shevchenko nvmem_unregister(nvmem); 913f1f50ecaSAndrey Smirnov } 914f1f50ecaSAndrey Smirnov 915f1f50ecaSAndrey Smirnov /** 916f1f50ecaSAndrey Smirnov * devm_nvmem_register() - Register a managed nvmem device for given 917f1f50ecaSAndrey Smirnov * nvmem_config. 9183a758071SAndreas Färber * Also creates a binary entry in /sys/bus/nvmem/devices/dev-name/nvmem 919f1f50ecaSAndrey Smirnov * 920b378c779SSrinivas Kandagatla * @dev: Device that uses the nvmem device. 921f1f50ecaSAndrey Smirnov * @config: nvmem device configuration with which nvmem device is created. 922f1f50ecaSAndrey Smirnov * 923f1f50ecaSAndrey Smirnov * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device 924f1f50ecaSAndrey Smirnov * on success. 925f1f50ecaSAndrey Smirnov */ 926f1f50ecaSAndrey Smirnov struct nvmem_device *devm_nvmem_register(struct device *dev, 927f1f50ecaSAndrey Smirnov const struct nvmem_config *config) 928f1f50ecaSAndrey Smirnov { 9295825b2c6SAndy Shevchenko struct nvmem_device *nvmem; 9305825b2c6SAndy Shevchenko int ret; 931f1f50ecaSAndrey Smirnov 932f1f50ecaSAndrey Smirnov nvmem = nvmem_register(config); 9335825b2c6SAndy Shevchenko if (IS_ERR(nvmem)) 9345825b2c6SAndy Shevchenko return nvmem; 935f1f50ecaSAndrey Smirnov 9365825b2c6SAndy Shevchenko ret = devm_add_action_or_reset(dev, devm_nvmem_unregister, nvmem); 9375825b2c6SAndy Shevchenko if (ret) 9385825b2c6SAndy Shevchenko return ERR_PTR(ret); 939f1f50ecaSAndrey Smirnov 940f1f50ecaSAndrey Smirnov return nvmem; 941f1f50ecaSAndrey Smirnov } 942f1f50ecaSAndrey Smirnov EXPORT_SYMBOL_GPL(devm_nvmem_register); 943f1f50ecaSAndrey Smirnov 9448c2a2b8cSThomas Bogendoerfer static struct nvmem_device *__nvmem_device_get(void *data, 9458c2a2b8cSThomas Bogendoerfer int (*match)(struct device *dev, const void *data)) 94669aba794SSrinivas Kandagatla { 94769aba794SSrinivas Kandagatla struct nvmem_device *nvmem = NULL; 9488c2a2b8cSThomas Bogendoerfer struct device *dev; 94969aba794SSrinivas Kandagatla 950c7235ee3SBartosz Golaszewski mutex_lock(&nvmem_mutex); 9518c2a2b8cSThomas Bogendoerfer dev = bus_find_device(&nvmem_bus_type, NULL, data, match); 9528c2a2b8cSThomas Bogendoerfer if (dev) 9538c2a2b8cSThomas Bogendoerfer nvmem = to_nvmem_device(dev); 95469aba794SSrinivas Kandagatla mutex_unlock(&nvmem_mutex); 955c7235ee3SBartosz Golaszewski if (!nvmem) 956c7235ee3SBartosz Golaszewski return ERR_PTR(-EPROBE_DEFER); 95769aba794SSrinivas Kandagatla 95869aba794SSrinivas Kandagatla if (!try_module_get(nvmem->owner)) { 95969aba794SSrinivas Kandagatla dev_err(&nvmem->dev, 96069aba794SSrinivas Kandagatla "could not increase module refcount for cell %s\n", 9615db652c9SBartosz Golaszewski nvmem_dev_name(nvmem)); 96269aba794SSrinivas Kandagatla 96373e9dc4dSAlban Bedel put_device(&nvmem->dev); 96469aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 96569aba794SSrinivas Kandagatla } 96669aba794SSrinivas Kandagatla 967c1de7f43SBartosz Golaszewski kref_get(&nvmem->refcnt); 968c1de7f43SBartosz Golaszewski 96969aba794SSrinivas Kandagatla return nvmem; 97069aba794SSrinivas Kandagatla } 97169aba794SSrinivas Kandagatla 97269aba794SSrinivas Kandagatla static void __nvmem_device_put(struct nvmem_device *nvmem) 97369aba794SSrinivas Kandagatla { 97473e9dc4dSAlban Bedel put_device(&nvmem->dev); 97569aba794SSrinivas Kandagatla module_put(nvmem->owner); 976c1de7f43SBartosz Golaszewski kref_put(&nvmem->refcnt, nvmem_device_release); 97769aba794SSrinivas Kandagatla } 97869aba794SSrinivas Kandagatla 979e701c67cSMasahiro Yamada #if IS_ENABLED(CONFIG_OF) 980e2a5402eSSrinivas Kandagatla /** 981e2a5402eSSrinivas Kandagatla * of_nvmem_device_get() - Get nvmem device from a given id 982e2a5402eSSrinivas Kandagatla * 98329143268SVivek Gautam * @np: Device tree node that uses the nvmem device. 984e2a5402eSSrinivas Kandagatla * @id: nvmem name from nvmem-names property. 985e2a5402eSSrinivas Kandagatla * 986e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device 987e2a5402eSSrinivas Kandagatla * on success. 988e2a5402eSSrinivas Kandagatla */ 989e2a5402eSSrinivas Kandagatla struct nvmem_device *of_nvmem_device_get(struct device_node *np, const char *id) 990e2a5402eSSrinivas Kandagatla { 991e2a5402eSSrinivas Kandagatla 992e2a5402eSSrinivas Kandagatla struct device_node *nvmem_np; 993b1c194dcSVadym Kochan struct nvmem_device *nvmem; 994d4e7fef1SAlban Bedel int index = 0; 995e2a5402eSSrinivas Kandagatla 996d4e7fef1SAlban Bedel if (id) 997e2a5402eSSrinivas Kandagatla index = of_property_match_string(np, "nvmem-names", id); 998e2a5402eSSrinivas Kandagatla 999e2a5402eSSrinivas Kandagatla nvmem_np = of_parse_phandle(np, "nvmem", index); 1000e2a5402eSSrinivas Kandagatla if (!nvmem_np) 1001d4e7fef1SAlban Bedel return ERR_PTR(-ENOENT); 1002e2a5402eSSrinivas Kandagatla 1003b1c194dcSVadym Kochan nvmem = __nvmem_device_get(nvmem_np, device_match_of_node); 1004b1c194dcSVadym Kochan of_node_put(nvmem_np); 1005b1c194dcSVadym Kochan return nvmem; 1006e2a5402eSSrinivas Kandagatla } 1007e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_nvmem_device_get); 1008e2a5402eSSrinivas Kandagatla #endif 1009e2a5402eSSrinivas Kandagatla 1010e2a5402eSSrinivas Kandagatla /** 1011e2a5402eSSrinivas Kandagatla * nvmem_device_get() - Get nvmem device from a given id 1012e2a5402eSSrinivas Kandagatla * 101329143268SVivek Gautam * @dev: Device that uses the nvmem device. 101429143268SVivek Gautam * @dev_name: name of the requested nvmem device. 1015e2a5402eSSrinivas Kandagatla * 1016e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device 1017e2a5402eSSrinivas Kandagatla * on success. 1018e2a5402eSSrinivas Kandagatla */ 1019e2a5402eSSrinivas Kandagatla struct nvmem_device *nvmem_device_get(struct device *dev, const char *dev_name) 1020e2a5402eSSrinivas Kandagatla { 1021e2a5402eSSrinivas Kandagatla if (dev->of_node) { /* try dt first */ 1022e2a5402eSSrinivas Kandagatla struct nvmem_device *nvmem; 1023e2a5402eSSrinivas Kandagatla 1024e2a5402eSSrinivas Kandagatla nvmem = of_nvmem_device_get(dev->of_node, dev_name); 1025e2a5402eSSrinivas Kandagatla 1026e2a5402eSSrinivas Kandagatla if (!IS_ERR(nvmem) || PTR_ERR(nvmem) == -EPROBE_DEFER) 1027e2a5402eSSrinivas Kandagatla return nvmem; 1028e2a5402eSSrinivas Kandagatla 1029e2a5402eSSrinivas Kandagatla } 1030e2a5402eSSrinivas Kandagatla 10318c2a2b8cSThomas Bogendoerfer return __nvmem_device_get((void *)dev_name, device_match_name); 1032e2a5402eSSrinivas Kandagatla } 1033e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_get); 1034e2a5402eSSrinivas Kandagatla 10358c2a2b8cSThomas Bogendoerfer /** 10368c2a2b8cSThomas Bogendoerfer * nvmem_device_find() - Find nvmem device with matching function 10378c2a2b8cSThomas Bogendoerfer * 10388c2a2b8cSThomas Bogendoerfer * @data: Data to pass to match function 10398c2a2b8cSThomas Bogendoerfer * @match: Callback function to check device 10408c2a2b8cSThomas Bogendoerfer * 10418c2a2b8cSThomas Bogendoerfer * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device 10428c2a2b8cSThomas Bogendoerfer * on success. 10438c2a2b8cSThomas Bogendoerfer */ 10448c2a2b8cSThomas Bogendoerfer struct nvmem_device *nvmem_device_find(void *data, 10458c2a2b8cSThomas Bogendoerfer int (*match)(struct device *dev, const void *data)) 10468c2a2b8cSThomas Bogendoerfer { 10478c2a2b8cSThomas Bogendoerfer return __nvmem_device_get(data, match); 10488c2a2b8cSThomas Bogendoerfer } 10498c2a2b8cSThomas Bogendoerfer EXPORT_SYMBOL_GPL(nvmem_device_find); 10508c2a2b8cSThomas Bogendoerfer 1051e2a5402eSSrinivas Kandagatla static int devm_nvmem_device_match(struct device *dev, void *res, void *data) 1052e2a5402eSSrinivas Kandagatla { 1053e2a5402eSSrinivas Kandagatla struct nvmem_device **nvmem = res; 1054e2a5402eSSrinivas Kandagatla 1055e2a5402eSSrinivas Kandagatla if (WARN_ON(!nvmem || !*nvmem)) 1056e2a5402eSSrinivas Kandagatla return 0; 1057e2a5402eSSrinivas Kandagatla 1058e2a5402eSSrinivas Kandagatla return *nvmem == data; 1059e2a5402eSSrinivas Kandagatla } 1060e2a5402eSSrinivas Kandagatla 1061e2a5402eSSrinivas Kandagatla static void devm_nvmem_device_release(struct device *dev, void *res) 1062e2a5402eSSrinivas Kandagatla { 1063e2a5402eSSrinivas Kandagatla nvmem_device_put(*(struct nvmem_device **)res); 1064e2a5402eSSrinivas Kandagatla } 1065e2a5402eSSrinivas Kandagatla 1066e2a5402eSSrinivas Kandagatla /** 1067e2a5402eSSrinivas Kandagatla * devm_nvmem_device_put() - put alredy got nvmem device 1068e2a5402eSSrinivas Kandagatla * 106929143268SVivek Gautam * @dev: Device that uses the nvmem device. 1070e2a5402eSSrinivas Kandagatla * @nvmem: pointer to nvmem device allocated by devm_nvmem_cell_get(), 1071e2a5402eSSrinivas Kandagatla * that needs to be released. 1072e2a5402eSSrinivas Kandagatla */ 1073e2a5402eSSrinivas Kandagatla void devm_nvmem_device_put(struct device *dev, struct nvmem_device *nvmem) 1074e2a5402eSSrinivas Kandagatla { 1075e2a5402eSSrinivas Kandagatla int ret; 1076e2a5402eSSrinivas Kandagatla 1077e2a5402eSSrinivas Kandagatla ret = devres_release(dev, devm_nvmem_device_release, 1078e2a5402eSSrinivas Kandagatla devm_nvmem_device_match, nvmem); 1079e2a5402eSSrinivas Kandagatla 1080e2a5402eSSrinivas Kandagatla WARN_ON(ret); 1081e2a5402eSSrinivas Kandagatla } 1082e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_device_put); 1083e2a5402eSSrinivas Kandagatla 1084e2a5402eSSrinivas Kandagatla /** 1085e2a5402eSSrinivas Kandagatla * nvmem_device_put() - put alredy got nvmem device 1086e2a5402eSSrinivas Kandagatla * 1087e2a5402eSSrinivas Kandagatla * @nvmem: pointer to nvmem device that needs to be released. 1088e2a5402eSSrinivas Kandagatla */ 1089e2a5402eSSrinivas Kandagatla void nvmem_device_put(struct nvmem_device *nvmem) 1090e2a5402eSSrinivas Kandagatla { 1091e2a5402eSSrinivas Kandagatla __nvmem_device_put(nvmem); 1092e2a5402eSSrinivas Kandagatla } 1093e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_put); 1094e2a5402eSSrinivas Kandagatla 1095e2a5402eSSrinivas Kandagatla /** 1096e2a5402eSSrinivas Kandagatla * devm_nvmem_device_get() - Get nvmem cell of device form a given id 1097e2a5402eSSrinivas Kandagatla * 109829143268SVivek Gautam * @dev: Device that requests the nvmem device. 109929143268SVivek Gautam * @id: name id for the requested nvmem device. 1100e2a5402eSSrinivas Kandagatla * 1101e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_cell 1102e2a5402eSSrinivas Kandagatla * on success. The nvmem_cell will be freed by the automatically once the 1103e2a5402eSSrinivas Kandagatla * device is freed. 1104e2a5402eSSrinivas Kandagatla */ 1105e2a5402eSSrinivas Kandagatla struct nvmem_device *devm_nvmem_device_get(struct device *dev, const char *id) 1106e2a5402eSSrinivas Kandagatla { 1107e2a5402eSSrinivas Kandagatla struct nvmem_device **ptr, *nvmem; 1108e2a5402eSSrinivas Kandagatla 1109e2a5402eSSrinivas Kandagatla ptr = devres_alloc(devm_nvmem_device_release, sizeof(*ptr), GFP_KERNEL); 1110e2a5402eSSrinivas Kandagatla if (!ptr) 1111e2a5402eSSrinivas Kandagatla return ERR_PTR(-ENOMEM); 1112e2a5402eSSrinivas Kandagatla 1113e2a5402eSSrinivas Kandagatla nvmem = nvmem_device_get(dev, id); 1114e2a5402eSSrinivas Kandagatla if (!IS_ERR(nvmem)) { 1115e2a5402eSSrinivas Kandagatla *ptr = nvmem; 1116e2a5402eSSrinivas Kandagatla devres_add(dev, ptr); 1117e2a5402eSSrinivas Kandagatla } else { 1118e2a5402eSSrinivas Kandagatla devres_free(ptr); 1119e2a5402eSSrinivas Kandagatla } 1120e2a5402eSSrinivas Kandagatla 1121e2a5402eSSrinivas Kandagatla return nvmem; 1122e2a5402eSSrinivas Kandagatla } 1123e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_device_get); 1124e2a5402eSSrinivas Kandagatla 11257ae6478bSSrinivas Kandagatla static struct nvmem_cell *nvmem_create_cell(struct nvmem_cell_entry *entry, const char *id) 11267ae6478bSSrinivas Kandagatla { 11277ae6478bSSrinivas Kandagatla struct nvmem_cell *cell; 11287ae6478bSSrinivas Kandagatla const char *name = NULL; 11297ae6478bSSrinivas Kandagatla 11307ae6478bSSrinivas Kandagatla cell = kzalloc(sizeof(*cell), GFP_KERNEL); 11317ae6478bSSrinivas Kandagatla if (!cell) 11327ae6478bSSrinivas Kandagatla return ERR_PTR(-ENOMEM); 11337ae6478bSSrinivas Kandagatla 11347ae6478bSSrinivas Kandagatla if (id) { 11357ae6478bSSrinivas Kandagatla name = kstrdup_const(id, GFP_KERNEL); 11367ae6478bSSrinivas Kandagatla if (!name) { 11377ae6478bSSrinivas Kandagatla kfree(cell); 11387ae6478bSSrinivas Kandagatla return ERR_PTR(-ENOMEM); 11397ae6478bSSrinivas Kandagatla } 11407ae6478bSSrinivas Kandagatla } 11417ae6478bSSrinivas Kandagatla 11427ae6478bSSrinivas Kandagatla cell->id = name; 11437ae6478bSSrinivas Kandagatla cell->entry = entry; 11447ae6478bSSrinivas Kandagatla 11457ae6478bSSrinivas Kandagatla return cell; 11467ae6478bSSrinivas Kandagatla } 11477ae6478bSSrinivas Kandagatla 1148506157beSBartosz Golaszewski static struct nvmem_cell * 1149506157beSBartosz Golaszewski nvmem_cell_get_from_lookup(struct device *dev, const char *con_id) 115069aba794SSrinivas Kandagatla { 11517ae6478bSSrinivas Kandagatla struct nvmem_cell_entry *cell_entry; 1152506157beSBartosz Golaszewski struct nvmem_cell *cell = ERR_PTR(-ENOENT); 1153506157beSBartosz Golaszewski struct nvmem_cell_lookup *lookup; 115469aba794SSrinivas Kandagatla struct nvmem_device *nvmem; 1155506157beSBartosz Golaszewski const char *dev_id; 115669aba794SSrinivas Kandagatla 1157506157beSBartosz Golaszewski if (!dev) 1158506157beSBartosz Golaszewski return ERR_PTR(-EINVAL); 115969aba794SSrinivas Kandagatla 1160506157beSBartosz Golaszewski dev_id = dev_name(dev); 1161506157beSBartosz Golaszewski 1162506157beSBartosz Golaszewski mutex_lock(&nvmem_lookup_mutex); 1163506157beSBartosz Golaszewski 1164506157beSBartosz Golaszewski list_for_each_entry(lookup, &nvmem_lookup_list, node) { 1165506157beSBartosz Golaszewski if ((strcmp(lookup->dev_id, dev_id) == 0) && 1166506157beSBartosz Golaszewski (strcmp(lookup->con_id, con_id) == 0)) { 1167506157beSBartosz Golaszewski /* This is the right entry. */ 11688c2a2b8cSThomas Bogendoerfer nvmem = __nvmem_device_get((void *)lookup->nvmem_name, 11698c2a2b8cSThomas Bogendoerfer device_match_name); 1170cccb3b19SBartosz Golaszewski if (IS_ERR(nvmem)) { 1171506157beSBartosz Golaszewski /* Provider may not be registered yet. */ 1172cccb3b19SBartosz Golaszewski cell = ERR_CAST(nvmem); 11739bfd8198SAlban Bedel break; 1174506157beSBartosz Golaszewski } 1175506157beSBartosz Golaszewski 11767ae6478bSSrinivas Kandagatla cell_entry = nvmem_find_cell_entry_by_name(nvmem, 1177506157beSBartosz Golaszewski lookup->cell_name); 11787ae6478bSSrinivas Kandagatla if (!cell_entry) { 1179506157beSBartosz Golaszewski __nvmem_device_put(nvmem); 1180cccb3b19SBartosz Golaszewski cell = ERR_PTR(-ENOENT); 11817ae6478bSSrinivas Kandagatla } else { 11827ae6478bSSrinivas Kandagatla cell = nvmem_create_cell(cell_entry, con_id); 11837ae6478bSSrinivas Kandagatla if (IS_ERR(cell)) 11847ae6478bSSrinivas Kandagatla __nvmem_device_put(nvmem); 1185506157beSBartosz Golaszewski } 11869bfd8198SAlban Bedel break; 1187506157beSBartosz Golaszewski } 1188506157beSBartosz Golaszewski } 1189506157beSBartosz Golaszewski 1190506157beSBartosz Golaszewski mutex_unlock(&nvmem_lookup_mutex); 119169aba794SSrinivas Kandagatla return cell; 119269aba794SSrinivas Kandagatla } 119369aba794SSrinivas Kandagatla 1194e701c67cSMasahiro Yamada #if IS_ENABLED(CONFIG_OF) 11957ae6478bSSrinivas Kandagatla static struct nvmem_cell_entry * 11967ae6478bSSrinivas Kandagatla nvmem_find_cell_entry_by_node(struct nvmem_device *nvmem, struct device_node *np) 11973c53e235SArnd Bergmann { 11987ae6478bSSrinivas Kandagatla struct nvmem_cell_entry *iter, *cell = NULL; 11993c53e235SArnd Bergmann 12003c53e235SArnd Bergmann mutex_lock(&nvmem_mutex); 12011c832674SAlban Bedel list_for_each_entry(iter, &nvmem->cells, node) { 12021c832674SAlban Bedel if (np == iter->np) { 12031c832674SAlban Bedel cell = iter; 12043c53e235SArnd Bergmann break; 12053c53e235SArnd Bergmann } 12061c832674SAlban Bedel } 12073c53e235SArnd Bergmann mutex_unlock(&nvmem_mutex); 12083c53e235SArnd Bergmann 12093c53e235SArnd Bergmann return cell; 12103c53e235SArnd Bergmann } 12113c53e235SArnd Bergmann 121269aba794SSrinivas Kandagatla /** 121369aba794SSrinivas Kandagatla * of_nvmem_cell_get() - Get a nvmem cell from given device node and cell id 121469aba794SSrinivas Kandagatla * 121529143268SVivek Gautam * @np: Device tree node that uses the nvmem cell. 1216165589f0SBartosz Golaszewski * @id: nvmem cell name from nvmem-cell-names property, or NULL 1217fd0c478cSVivek Gautam * for the cell at index 0 (the lone cell with no accompanying 1218fd0c478cSVivek Gautam * nvmem-cell-names property). 121969aba794SSrinivas Kandagatla * 122069aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 122169aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 122269aba794SSrinivas Kandagatla * nvmem_cell_put(). 122369aba794SSrinivas Kandagatla */ 1224165589f0SBartosz Golaszewski struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *id) 122569aba794SSrinivas Kandagatla { 122669aba794SSrinivas Kandagatla struct device_node *cell_np, *nvmem_np; 122769aba794SSrinivas Kandagatla struct nvmem_device *nvmem; 12287ae6478bSSrinivas Kandagatla struct nvmem_cell_entry *cell_entry; 1229e888d445SBartosz Golaszewski struct nvmem_cell *cell; 1230fd0c478cSVivek Gautam int index = 0; 123169aba794SSrinivas Kandagatla 1232fd0c478cSVivek Gautam /* if cell name exists, find index to the name */ 1233165589f0SBartosz Golaszewski if (id) 1234165589f0SBartosz Golaszewski index = of_property_match_string(np, "nvmem-cell-names", id); 123569aba794SSrinivas Kandagatla 123669aba794SSrinivas Kandagatla cell_np = of_parse_phandle(np, "nvmem-cells", index); 123769aba794SSrinivas Kandagatla if (!cell_np) 12385087cc19SAlban Bedel return ERR_PTR(-ENOENT); 123969aba794SSrinivas Kandagatla 1240*edcf2fb6SMichael Walle nvmem_np = of_get_parent(cell_np); 1241*edcf2fb6SMichael Walle if (!nvmem_np) { 1242*edcf2fb6SMichael Walle of_node_put(cell_np); 124369aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 1244*edcf2fb6SMichael Walle } 124569aba794SSrinivas Kandagatla 12468c2a2b8cSThomas Bogendoerfer nvmem = __nvmem_device_get(nvmem_np, device_match_of_node); 1247aad8d097SMasahiro Yamada of_node_put(nvmem_np); 1248*edcf2fb6SMichael Walle if (IS_ERR(nvmem)) { 1249*edcf2fb6SMichael Walle of_node_put(cell_np); 125069aba794SSrinivas Kandagatla return ERR_CAST(nvmem); 1251*edcf2fb6SMichael Walle } 125269aba794SSrinivas Kandagatla 12537ae6478bSSrinivas Kandagatla cell_entry = nvmem_find_cell_entry_by_node(nvmem, cell_np); 1254*edcf2fb6SMichael Walle of_node_put(cell_np); 12557ae6478bSSrinivas Kandagatla if (!cell_entry) { 1256e888d445SBartosz Golaszewski __nvmem_device_put(nvmem); 1257e888d445SBartosz Golaszewski return ERR_PTR(-ENOENT); 125869aba794SSrinivas Kandagatla } 125969aba794SSrinivas Kandagatla 12607ae6478bSSrinivas Kandagatla cell = nvmem_create_cell(cell_entry, id); 12617ae6478bSSrinivas Kandagatla if (IS_ERR(cell)) 12627ae6478bSSrinivas Kandagatla __nvmem_device_put(nvmem); 12637ae6478bSSrinivas Kandagatla 126469aba794SSrinivas Kandagatla return cell; 126569aba794SSrinivas Kandagatla } 126669aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_nvmem_cell_get); 126769aba794SSrinivas Kandagatla #endif 126869aba794SSrinivas Kandagatla 126969aba794SSrinivas Kandagatla /** 127069aba794SSrinivas Kandagatla * nvmem_cell_get() - Get nvmem cell of device form a given cell name 127169aba794SSrinivas Kandagatla * 127229143268SVivek Gautam * @dev: Device that requests the nvmem cell. 1273165589f0SBartosz Golaszewski * @id: nvmem cell name to get (this corresponds with the name from the 1274165589f0SBartosz Golaszewski * nvmem-cell-names property for DT systems and with the con_id from 1275165589f0SBartosz Golaszewski * the lookup entry for non-DT systems). 127669aba794SSrinivas Kandagatla * 127769aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 127869aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 127969aba794SSrinivas Kandagatla * nvmem_cell_put(). 128069aba794SSrinivas Kandagatla */ 1281165589f0SBartosz Golaszewski struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *id) 128269aba794SSrinivas Kandagatla { 128369aba794SSrinivas Kandagatla struct nvmem_cell *cell; 128469aba794SSrinivas Kandagatla 128569aba794SSrinivas Kandagatla if (dev->of_node) { /* try dt first */ 1286165589f0SBartosz Golaszewski cell = of_nvmem_cell_get(dev->of_node, id); 128769aba794SSrinivas Kandagatla if (!IS_ERR(cell) || PTR_ERR(cell) == -EPROBE_DEFER) 128869aba794SSrinivas Kandagatla return cell; 128969aba794SSrinivas Kandagatla } 129069aba794SSrinivas Kandagatla 1291165589f0SBartosz Golaszewski /* NULL cell id only allowed for device tree; invalid otherwise */ 1292165589f0SBartosz Golaszewski if (!id) 129387ed1405SDouglas Anderson return ERR_PTR(-EINVAL); 129487ed1405SDouglas Anderson 1295165589f0SBartosz Golaszewski return nvmem_cell_get_from_lookup(dev, id); 129669aba794SSrinivas Kandagatla } 129769aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_get); 129869aba794SSrinivas Kandagatla 129969aba794SSrinivas Kandagatla static void devm_nvmem_cell_release(struct device *dev, void *res) 130069aba794SSrinivas Kandagatla { 130169aba794SSrinivas Kandagatla nvmem_cell_put(*(struct nvmem_cell **)res); 130269aba794SSrinivas Kandagatla } 130369aba794SSrinivas Kandagatla 130469aba794SSrinivas Kandagatla /** 130569aba794SSrinivas Kandagatla * devm_nvmem_cell_get() - Get nvmem cell of device form a given id 130669aba794SSrinivas Kandagatla * 130729143268SVivek Gautam * @dev: Device that requests the nvmem cell. 130829143268SVivek Gautam * @id: nvmem cell name id to get. 130969aba794SSrinivas Kandagatla * 131069aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 131169aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 131269aba794SSrinivas Kandagatla * automatically once the device is freed. 131369aba794SSrinivas Kandagatla */ 131469aba794SSrinivas Kandagatla struct nvmem_cell *devm_nvmem_cell_get(struct device *dev, const char *id) 131569aba794SSrinivas Kandagatla { 131669aba794SSrinivas Kandagatla struct nvmem_cell **ptr, *cell; 131769aba794SSrinivas Kandagatla 131869aba794SSrinivas Kandagatla ptr = devres_alloc(devm_nvmem_cell_release, sizeof(*ptr), GFP_KERNEL); 131969aba794SSrinivas Kandagatla if (!ptr) 132069aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 132169aba794SSrinivas Kandagatla 132269aba794SSrinivas Kandagatla cell = nvmem_cell_get(dev, id); 132369aba794SSrinivas Kandagatla if (!IS_ERR(cell)) { 132469aba794SSrinivas Kandagatla *ptr = cell; 132569aba794SSrinivas Kandagatla devres_add(dev, ptr); 132669aba794SSrinivas Kandagatla } else { 132769aba794SSrinivas Kandagatla devres_free(ptr); 132869aba794SSrinivas Kandagatla } 132969aba794SSrinivas Kandagatla 133069aba794SSrinivas Kandagatla return cell; 133169aba794SSrinivas Kandagatla } 133269aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_cell_get); 133369aba794SSrinivas Kandagatla 133469aba794SSrinivas Kandagatla static int devm_nvmem_cell_match(struct device *dev, void *res, void *data) 133569aba794SSrinivas Kandagatla { 133669aba794SSrinivas Kandagatla struct nvmem_cell **c = res; 133769aba794SSrinivas Kandagatla 133869aba794SSrinivas Kandagatla if (WARN_ON(!c || !*c)) 133969aba794SSrinivas Kandagatla return 0; 134069aba794SSrinivas Kandagatla 134169aba794SSrinivas Kandagatla return *c == data; 134269aba794SSrinivas Kandagatla } 134369aba794SSrinivas Kandagatla 134469aba794SSrinivas Kandagatla /** 134569aba794SSrinivas Kandagatla * devm_nvmem_cell_put() - Release previously allocated nvmem cell 134669aba794SSrinivas Kandagatla * from devm_nvmem_cell_get. 134769aba794SSrinivas Kandagatla * 134829143268SVivek Gautam * @dev: Device that requests the nvmem cell. 134929143268SVivek Gautam * @cell: Previously allocated nvmem cell by devm_nvmem_cell_get(). 135069aba794SSrinivas Kandagatla */ 135169aba794SSrinivas Kandagatla void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell) 135269aba794SSrinivas Kandagatla { 135369aba794SSrinivas Kandagatla int ret; 135469aba794SSrinivas Kandagatla 135569aba794SSrinivas Kandagatla ret = devres_release(dev, devm_nvmem_cell_release, 135669aba794SSrinivas Kandagatla devm_nvmem_cell_match, cell); 135769aba794SSrinivas Kandagatla 135869aba794SSrinivas Kandagatla WARN_ON(ret); 135969aba794SSrinivas Kandagatla } 136069aba794SSrinivas Kandagatla EXPORT_SYMBOL(devm_nvmem_cell_put); 136169aba794SSrinivas Kandagatla 136269aba794SSrinivas Kandagatla /** 136369aba794SSrinivas Kandagatla * nvmem_cell_put() - Release previously allocated nvmem cell. 136469aba794SSrinivas Kandagatla * 136529143268SVivek Gautam * @cell: Previously allocated nvmem cell by nvmem_cell_get(). 136669aba794SSrinivas Kandagatla */ 136769aba794SSrinivas Kandagatla void nvmem_cell_put(struct nvmem_cell *cell) 136869aba794SSrinivas Kandagatla { 13697ae6478bSSrinivas Kandagatla struct nvmem_device *nvmem = cell->entry->nvmem; 137069aba794SSrinivas Kandagatla 13717ae6478bSSrinivas Kandagatla if (cell->id) 13727ae6478bSSrinivas Kandagatla kfree_const(cell->id); 13737ae6478bSSrinivas Kandagatla 13747ae6478bSSrinivas Kandagatla kfree(cell); 137569aba794SSrinivas Kandagatla __nvmem_device_put(nvmem); 137669aba794SSrinivas Kandagatla } 137769aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_put); 137869aba794SSrinivas Kandagatla 13797ae6478bSSrinivas Kandagatla static void nvmem_shift_read_buffer_in_place(struct nvmem_cell_entry *cell, void *buf) 138069aba794SSrinivas Kandagatla { 138169aba794SSrinivas Kandagatla u8 *p, *b; 13822fe518feSJorge Ramirez-Ortiz int i, extra, bit_offset = cell->bit_offset; 138369aba794SSrinivas Kandagatla 138469aba794SSrinivas Kandagatla p = b = buf; 138569aba794SSrinivas Kandagatla if (bit_offset) { 138669aba794SSrinivas Kandagatla /* First shift */ 138769aba794SSrinivas Kandagatla *b++ >>= bit_offset; 138869aba794SSrinivas Kandagatla 138969aba794SSrinivas Kandagatla /* setup rest of the bytes if any */ 139069aba794SSrinivas Kandagatla for (i = 1; i < cell->bytes; i++) { 139169aba794SSrinivas Kandagatla /* Get bits from next byte and shift them towards msb */ 139269aba794SSrinivas Kandagatla *p |= *b << (BITS_PER_BYTE - bit_offset); 139369aba794SSrinivas Kandagatla 139469aba794SSrinivas Kandagatla p = b; 139569aba794SSrinivas Kandagatla *b++ >>= bit_offset; 139669aba794SSrinivas Kandagatla } 13972fe518feSJorge Ramirez-Ortiz } else { 13982fe518feSJorge Ramirez-Ortiz /* point to the msb */ 13992fe518feSJorge Ramirez-Ortiz p += cell->bytes - 1; 14002fe518feSJorge Ramirez-Ortiz } 140169aba794SSrinivas Kandagatla 140269aba794SSrinivas Kandagatla /* result fits in less bytes */ 14032fe518feSJorge Ramirez-Ortiz extra = cell->bytes - DIV_ROUND_UP(cell->nbits, BITS_PER_BYTE); 14042fe518feSJorge Ramirez-Ortiz while (--extra >= 0) 140569aba794SSrinivas Kandagatla *p-- = 0; 14062fe518feSJorge Ramirez-Ortiz 140769aba794SSrinivas Kandagatla /* clear msb bits if any leftover in the last byte */ 14085d388fa0SStephen Boyd if (cell->nbits % BITS_PER_BYTE) 140969aba794SSrinivas Kandagatla *p &= GENMASK((cell->nbits % BITS_PER_BYTE) - 1, 0); 141069aba794SSrinivas Kandagatla } 141169aba794SSrinivas Kandagatla 141269aba794SSrinivas Kandagatla static int __nvmem_cell_read(struct nvmem_device *nvmem, 14137ae6478bSSrinivas Kandagatla struct nvmem_cell_entry *cell, 14147ae6478bSSrinivas Kandagatla void *buf, size_t *len, const char *id) 141569aba794SSrinivas Kandagatla { 141669aba794SSrinivas Kandagatla int rc; 141769aba794SSrinivas Kandagatla 1418795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, cell->offset, buf, cell->bytes); 141969aba794SSrinivas Kandagatla 1420287980e4SArnd Bergmann if (rc) 142169aba794SSrinivas Kandagatla return rc; 142269aba794SSrinivas Kandagatla 142369aba794SSrinivas Kandagatla /* shift bits in-place */ 1424cbf854abSAxel Lin if (cell->bit_offset || cell->nbits) 142569aba794SSrinivas Kandagatla nvmem_shift_read_buffer_in_place(cell, buf); 142669aba794SSrinivas Kandagatla 14275008062fSSrinivas Kandagatla if (nvmem->cell_post_process) { 14285008062fSSrinivas Kandagatla rc = nvmem->cell_post_process(nvmem->priv, id, 14295008062fSSrinivas Kandagatla cell->offset, buf, cell->bytes); 14305008062fSSrinivas Kandagatla if (rc) 14315008062fSSrinivas Kandagatla return rc; 14325008062fSSrinivas Kandagatla } 14335008062fSSrinivas Kandagatla 14343b4a6877SVivek Gautam if (len) 143569aba794SSrinivas Kandagatla *len = cell->bytes; 143669aba794SSrinivas Kandagatla 143769aba794SSrinivas Kandagatla return 0; 143869aba794SSrinivas Kandagatla } 143969aba794SSrinivas Kandagatla 144069aba794SSrinivas Kandagatla /** 144169aba794SSrinivas Kandagatla * nvmem_cell_read() - Read a given nvmem cell 144269aba794SSrinivas Kandagatla * 144369aba794SSrinivas Kandagatla * @cell: nvmem cell to be read. 14443b4a6877SVivek Gautam * @len: pointer to length of cell which will be populated on successful read; 14453b4a6877SVivek Gautam * can be NULL. 144669aba794SSrinivas Kandagatla * 1447b577fafcSBrian Norris * Return: ERR_PTR() on error or a valid pointer to a buffer on success. The 1448b577fafcSBrian Norris * buffer should be freed by the consumer with a kfree(). 144969aba794SSrinivas Kandagatla */ 145069aba794SSrinivas Kandagatla void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len) 145169aba794SSrinivas Kandagatla { 14527ae6478bSSrinivas Kandagatla struct nvmem_device *nvmem = cell->entry->nvmem; 145369aba794SSrinivas Kandagatla u8 *buf; 145469aba794SSrinivas Kandagatla int rc; 145569aba794SSrinivas Kandagatla 1456795ddd18SSrinivas Kandagatla if (!nvmem) 145769aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 145869aba794SSrinivas Kandagatla 14597ae6478bSSrinivas Kandagatla buf = kzalloc(cell->entry->bytes, GFP_KERNEL); 146069aba794SSrinivas Kandagatla if (!buf) 146169aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 146269aba794SSrinivas Kandagatla 14637ae6478bSSrinivas Kandagatla rc = __nvmem_cell_read(nvmem, cell->entry, buf, len, cell->id); 1464287980e4SArnd Bergmann if (rc) { 146569aba794SSrinivas Kandagatla kfree(buf); 146669aba794SSrinivas Kandagatla return ERR_PTR(rc); 146769aba794SSrinivas Kandagatla } 146869aba794SSrinivas Kandagatla 146969aba794SSrinivas Kandagatla return buf; 147069aba794SSrinivas Kandagatla } 147169aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_read); 147269aba794SSrinivas Kandagatla 14737ae6478bSSrinivas Kandagatla static void *nvmem_cell_prepare_write_buffer(struct nvmem_cell_entry *cell, 147469aba794SSrinivas Kandagatla u8 *_buf, int len) 147569aba794SSrinivas Kandagatla { 147669aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 147769aba794SSrinivas Kandagatla int i, rc, nbits, bit_offset = cell->bit_offset; 147869aba794SSrinivas Kandagatla u8 v, *p, *buf, *b, pbyte, pbits; 147969aba794SSrinivas Kandagatla 148069aba794SSrinivas Kandagatla nbits = cell->nbits; 148169aba794SSrinivas Kandagatla buf = kzalloc(cell->bytes, GFP_KERNEL); 148269aba794SSrinivas Kandagatla if (!buf) 148369aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 148469aba794SSrinivas Kandagatla 148569aba794SSrinivas Kandagatla memcpy(buf, _buf, len); 148669aba794SSrinivas Kandagatla p = b = buf; 148769aba794SSrinivas Kandagatla 148869aba794SSrinivas Kandagatla if (bit_offset) { 148969aba794SSrinivas Kandagatla pbyte = *b; 149069aba794SSrinivas Kandagatla *b <<= bit_offset; 149169aba794SSrinivas Kandagatla 149269aba794SSrinivas Kandagatla /* setup the first byte with lsb bits from nvmem */ 1493795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, cell->offset, &v, 1); 149450808bfcSMathieu Malaterre if (rc) 149550808bfcSMathieu Malaterre goto err; 149669aba794SSrinivas Kandagatla *b++ |= GENMASK(bit_offset - 1, 0) & v; 149769aba794SSrinivas Kandagatla 149869aba794SSrinivas Kandagatla /* setup rest of the byte if any */ 149969aba794SSrinivas Kandagatla for (i = 1; i < cell->bytes; i++) { 150069aba794SSrinivas Kandagatla /* Get last byte bits and shift them towards lsb */ 150169aba794SSrinivas Kandagatla pbits = pbyte >> (BITS_PER_BYTE - 1 - bit_offset); 150269aba794SSrinivas Kandagatla pbyte = *b; 150369aba794SSrinivas Kandagatla p = b; 150469aba794SSrinivas Kandagatla *b <<= bit_offset; 150569aba794SSrinivas Kandagatla *b++ |= pbits; 150669aba794SSrinivas Kandagatla } 150769aba794SSrinivas Kandagatla } 150869aba794SSrinivas Kandagatla 150969aba794SSrinivas Kandagatla /* if it's not end on byte boundary */ 151069aba794SSrinivas Kandagatla if ((nbits + bit_offset) % BITS_PER_BYTE) { 151169aba794SSrinivas Kandagatla /* setup the last byte with msb bits from nvmem */ 1512795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, 151369aba794SSrinivas Kandagatla cell->offset + cell->bytes - 1, &v, 1); 151450808bfcSMathieu Malaterre if (rc) 151550808bfcSMathieu Malaterre goto err; 151669aba794SSrinivas Kandagatla *p |= GENMASK(7, (nbits + bit_offset) % BITS_PER_BYTE) & v; 151769aba794SSrinivas Kandagatla 151869aba794SSrinivas Kandagatla } 151969aba794SSrinivas Kandagatla 152069aba794SSrinivas Kandagatla return buf; 152150808bfcSMathieu Malaterre err: 152250808bfcSMathieu Malaterre kfree(buf); 152350808bfcSMathieu Malaterre return ERR_PTR(rc); 152469aba794SSrinivas Kandagatla } 152569aba794SSrinivas Kandagatla 15267ae6478bSSrinivas Kandagatla static int __nvmem_cell_entry_write(struct nvmem_cell_entry *cell, void *buf, size_t len) 152769aba794SSrinivas Kandagatla { 152869aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 152969aba794SSrinivas Kandagatla int rc; 153069aba794SSrinivas Kandagatla 1531795ddd18SSrinivas Kandagatla if (!nvmem || nvmem->read_only || 153269aba794SSrinivas Kandagatla (cell->bit_offset == 0 && len != cell->bytes)) 153369aba794SSrinivas Kandagatla return -EINVAL; 153469aba794SSrinivas Kandagatla 153569aba794SSrinivas Kandagatla if (cell->bit_offset || cell->nbits) { 153669aba794SSrinivas Kandagatla buf = nvmem_cell_prepare_write_buffer(cell, buf, len); 153769aba794SSrinivas Kandagatla if (IS_ERR(buf)) 153869aba794SSrinivas Kandagatla return PTR_ERR(buf); 153969aba794SSrinivas Kandagatla } 154069aba794SSrinivas Kandagatla 1541795ddd18SSrinivas Kandagatla rc = nvmem_reg_write(nvmem, cell->offset, buf, cell->bytes); 154269aba794SSrinivas Kandagatla 154369aba794SSrinivas Kandagatla /* free the tmp buffer */ 1544ace22170SAxel Lin if (cell->bit_offset || cell->nbits) 154569aba794SSrinivas Kandagatla kfree(buf); 154669aba794SSrinivas Kandagatla 1547287980e4SArnd Bergmann if (rc) 154869aba794SSrinivas Kandagatla return rc; 154969aba794SSrinivas Kandagatla 155069aba794SSrinivas Kandagatla return len; 155169aba794SSrinivas Kandagatla } 15527ae6478bSSrinivas Kandagatla 15537ae6478bSSrinivas Kandagatla /** 15547ae6478bSSrinivas Kandagatla * nvmem_cell_write() - Write to a given nvmem cell 15557ae6478bSSrinivas Kandagatla * 15567ae6478bSSrinivas Kandagatla * @cell: nvmem cell to be written. 15577ae6478bSSrinivas Kandagatla * @buf: Buffer to be written. 15587ae6478bSSrinivas Kandagatla * @len: length of buffer to be written to nvmem cell. 15597ae6478bSSrinivas Kandagatla * 15607ae6478bSSrinivas Kandagatla * Return: length of bytes written or negative on failure. 15617ae6478bSSrinivas Kandagatla */ 15627ae6478bSSrinivas Kandagatla int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len) 15637ae6478bSSrinivas Kandagatla { 15647ae6478bSSrinivas Kandagatla return __nvmem_cell_entry_write(cell->entry, buf, len); 15657ae6478bSSrinivas Kandagatla } 15667ae6478bSSrinivas Kandagatla 156769aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_write); 156869aba794SSrinivas Kandagatla 15696bb317ceSYangtao Li static int nvmem_cell_read_common(struct device *dev, const char *cell_id, 15706bb317ceSYangtao Li void *val, size_t count) 15710a9b2d1cSFabrice Gasnier { 15720a9b2d1cSFabrice Gasnier struct nvmem_cell *cell; 15730a9b2d1cSFabrice Gasnier void *buf; 15740a9b2d1cSFabrice Gasnier size_t len; 15750a9b2d1cSFabrice Gasnier 15760a9b2d1cSFabrice Gasnier cell = nvmem_cell_get(dev, cell_id); 15770a9b2d1cSFabrice Gasnier if (IS_ERR(cell)) 15780a9b2d1cSFabrice Gasnier return PTR_ERR(cell); 15790a9b2d1cSFabrice Gasnier 15800a9b2d1cSFabrice Gasnier buf = nvmem_cell_read(cell, &len); 15810a9b2d1cSFabrice Gasnier if (IS_ERR(buf)) { 15820a9b2d1cSFabrice Gasnier nvmem_cell_put(cell); 15830a9b2d1cSFabrice Gasnier return PTR_ERR(buf); 15840a9b2d1cSFabrice Gasnier } 15856bb317ceSYangtao Li if (len != count) { 15860a9b2d1cSFabrice Gasnier kfree(buf); 15870a9b2d1cSFabrice Gasnier nvmem_cell_put(cell); 15880a9b2d1cSFabrice Gasnier return -EINVAL; 15890a9b2d1cSFabrice Gasnier } 15906bb317ceSYangtao Li memcpy(val, buf, count); 15910a9b2d1cSFabrice Gasnier kfree(buf); 15920a9b2d1cSFabrice Gasnier nvmem_cell_put(cell); 15930a9b2d1cSFabrice Gasnier 15940a9b2d1cSFabrice Gasnier return 0; 15950a9b2d1cSFabrice Gasnier } 15966bb317ceSYangtao Li 15976bb317ceSYangtao Li /** 15985037d368SAndreas Färber * nvmem_cell_read_u8() - Read a cell value as a u8 15995037d368SAndreas Färber * 16005037d368SAndreas Färber * @dev: Device that requests the nvmem cell. 16015037d368SAndreas Färber * @cell_id: Name of nvmem cell to read. 16025037d368SAndreas Färber * @val: pointer to output value. 16035037d368SAndreas Färber * 16045037d368SAndreas Färber * Return: 0 on success or negative errno. 16055037d368SAndreas Färber */ 16065037d368SAndreas Färber int nvmem_cell_read_u8(struct device *dev, const char *cell_id, u8 *val) 16075037d368SAndreas Färber { 16085037d368SAndreas Färber return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val)); 16095037d368SAndreas Färber } 16105037d368SAndreas Färber EXPORT_SYMBOL_GPL(nvmem_cell_read_u8); 16115037d368SAndreas Färber 16125037d368SAndreas Färber /** 16133a758071SAndreas Färber * nvmem_cell_read_u16() - Read a cell value as a u16 16146bb317ceSYangtao Li * 16156bb317ceSYangtao Li * @dev: Device that requests the nvmem cell. 16166bb317ceSYangtao Li * @cell_id: Name of nvmem cell to read. 16176bb317ceSYangtao Li * @val: pointer to output value. 16186bb317ceSYangtao Li * 16196bb317ceSYangtao Li * Return: 0 on success or negative errno. 16206bb317ceSYangtao Li */ 16216bb317ceSYangtao Li int nvmem_cell_read_u16(struct device *dev, const char *cell_id, u16 *val) 16226bb317ceSYangtao Li { 16236bb317ceSYangtao Li return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val)); 16246bb317ceSYangtao Li } 16250a9b2d1cSFabrice Gasnier EXPORT_SYMBOL_GPL(nvmem_cell_read_u16); 16260a9b2d1cSFabrice Gasnier 16270a9b2d1cSFabrice Gasnier /** 16283a758071SAndreas Färber * nvmem_cell_read_u32() - Read a cell value as a u32 1629d026d70aSLeonard Crestez * 1630d026d70aSLeonard Crestez * @dev: Device that requests the nvmem cell. 1631d026d70aSLeonard Crestez * @cell_id: Name of nvmem cell to read. 1632d026d70aSLeonard Crestez * @val: pointer to output value. 1633d026d70aSLeonard Crestez * 1634d026d70aSLeonard Crestez * Return: 0 on success or negative errno. 1635d026d70aSLeonard Crestez */ 1636d026d70aSLeonard Crestez int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val) 1637d026d70aSLeonard Crestez { 16386bb317ceSYangtao Li return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val)); 1639d026d70aSLeonard Crestez } 1640d026d70aSLeonard Crestez EXPORT_SYMBOL_GPL(nvmem_cell_read_u32); 1641d026d70aSLeonard Crestez 1642d026d70aSLeonard Crestez /** 16433a758071SAndreas Färber * nvmem_cell_read_u64() - Read a cell value as a u64 16448b977c54SYangtao Li * 16458b977c54SYangtao Li * @dev: Device that requests the nvmem cell. 16468b977c54SYangtao Li * @cell_id: Name of nvmem cell to read. 16478b977c54SYangtao Li * @val: pointer to output value. 16488b977c54SYangtao Li * 16498b977c54SYangtao Li * Return: 0 on success or negative errno. 16508b977c54SYangtao Li */ 16518b977c54SYangtao Li int nvmem_cell_read_u64(struct device *dev, const char *cell_id, u64 *val) 16528b977c54SYangtao Li { 16538b977c54SYangtao Li return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val)); 16548b977c54SYangtao Li } 16558b977c54SYangtao Li EXPORT_SYMBOL_GPL(nvmem_cell_read_u64); 16568b977c54SYangtao Li 16571f7b4d87SDouglas Anderson static const void *nvmem_cell_read_variable_common(struct device *dev, 1658a28e824fSDouglas Anderson const char *cell_id, 1659a28e824fSDouglas Anderson size_t max_len, size_t *len) 1660a28e824fSDouglas Anderson { 1661a28e824fSDouglas Anderson struct nvmem_cell *cell; 1662a28e824fSDouglas Anderson int nbits; 1663a28e824fSDouglas Anderson void *buf; 1664a28e824fSDouglas Anderson 1665a28e824fSDouglas Anderson cell = nvmem_cell_get(dev, cell_id); 1666a28e824fSDouglas Anderson if (IS_ERR(cell)) 1667a28e824fSDouglas Anderson return cell; 1668a28e824fSDouglas Anderson 16697ae6478bSSrinivas Kandagatla nbits = cell->entry->nbits; 1670a28e824fSDouglas Anderson buf = nvmem_cell_read(cell, len); 1671a28e824fSDouglas Anderson nvmem_cell_put(cell); 1672a28e824fSDouglas Anderson if (IS_ERR(buf)) 1673a28e824fSDouglas Anderson return buf; 1674a28e824fSDouglas Anderson 1675a28e824fSDouglas Anderson /* 1676a28e824fSDouglas Anderson * If nbits is set then nvmem_cell_read() can significantly exaggerate 1677a28e824fSDouglas Anderson * the length of the real data. Throw away the extra junk. 1678a28e824fSDouglas Anderson */ 1679a28e824fSDouglas Anderson if (nbits) 1680a28e824fSDouglas Anderson *len = DIV_ROUND_UP(nbits, 8); 1681a28e824fSDouglas Anderson 1682a28e824fSDouglas Anderson if (*len > max_len) { 1683a28e824fSDouglas Anderson kfree(buf); 1684a28e824fSDouglas Anderson return ERR_PTR(-ERANGE); 1685a28e824fSDouglas Anderson } 1686a28e824fSDouglas Anderson 1687a28e824fSDouglas Anderson return buf; 1688a28e824fSDouglas Anderson } 1689a28e824fSDouglas Anderson 1690a28e824fSDouglas Anderson /** 1691a28e824fSDouglas Anderson * nvmem_cell_read_variable_le_u32() - Read up to 32-bits of data as a little endian number. 1692a28e824fSDouglas Anderson * 1693a28e824fSDouglas Anderson * @dev: Device that requests the nvmem cell. 1694a28e824fSDouglas Anderson * @cell_id: Name of nvmem cell to read. 1695a28e824fSDouglas Anderson * @val: pointer to output value. 1696a28e824fSDouglas Anderson * 1697a28e824fSDouglas Anderson * Return: 0 on success or negative errno. 1698a28e824fSDouglas Anderson */ 1699a28e824fSDouglas Anderson int nvmem_cell_read_variable_le_u32(struct device *dev, const char *cell_id, 1700a28e824fSDouglas Anderson u32 *val) 1701a28e824fSDouglas Anderson { 1702a28e824fSDouglas Anderson size_t len; 17031f7b4d87SDouglas Anderson const u8 *buf; 1704a28e824fSDouglas Anderson int i; 1705a28e824fSDouglas Anderson 1706a28e824fSDouglas Anderson buf = nvmem_cell_read_variable_common(dev, cell_id, sizeof(*val), &len); 1707a28e824fSDouglas Anderson if (IS_ERR(buf)) 1708a28e824fSDouglas Anderson return PTR_ERR(buf); 1709a28e824fSDouglas Anderson 1710a28e824fSDouglas Anderson /* Copy w/ implicit endian conversion */ 1711a28e824fSDouglas Anderson *val = 0; 1712a28e824fSDouglas Anderson for (i = 0; i < len; i++) 1713a28e824fSDouglas Anderson *val |= buf[i] << (8 * i); 1714a28e824fSDouglas Anderson 1715a28e824fSDouglas Anderson kfree(buf); 1716a28e824fSDouglas Anderson 1717a28e824fSDouglas Anderson return 0; 1718a28e824fSDouglas Anderson } 1719a28e824fSDouglas Anderson EXPORT_SYMBOL_GPL(nvmem_cell_read_variable_le_u32); 1720a28e824fSDouglas Anderson 1721a28e824fSDouglas Anderson /** 1722a28e824fSDouglas Anderson * nvmem_cell_read_variable_le_u64() - Read up to 64-bits of data as a little endian number. 1723a28e824fSDouglas Anderson * 1724a28e824fSDouglas Anderson * @dev: Device that requests the nvmem cell. 1725a28e824fSDouglas Anderson * @cell_id: Name of nvmem cell to read. 1726a28e824fSDouglas Anderson * @val: pointer to output value. 1727a28e824fSDouglas Anderson * 1728a28e824fSDouglas Anderson * Return: 0 on success or negative errno. 1729a28e824fSDouglas Anderson */ 1730a28e824fSDouglas Anderson int nvmem_cell_read_variable_le_u64(struct device *dev, const char *cell_id, 1731a28e824fSDouglas Anderson u64 *val) 1732a28e824fSDouglas Anderson { 1733a28e824fSDouglas Anderson size_t len; 17341f7b4d87SDouglas Anderson const u8 *buf; 1735a28e824fSDouglas Anderson int i; 1736a28e824fSDouglas Anderson 1737a28e824fSDouglas Anderson buf = nvmem_cell_read_variable_common(dev, cell_id, sizeof(*val), &len); 1738a28e824fSDouglas Anderson if (IS_ERR(buf)) 1739a28e824fSDouglas Anderson return PTR_ERR(buf); 1740a28e824fSDouglas Anderson 1741a28e824fSDouglas Anderson /* Copy w/ implicit endian conversion */ 1742a28e824fSDouglas Anderson *val = 0; 1743a28e824fSDouglas Anderson for (i = 0; i < len; i++) 174455022fdeSColin Ian King *val |= (uint64_t)buf[i] << (8 * i); 1745a28e824fSDouglas Anderson 1746a28e824fSDouglas Anderson kfree(buf); 1747a28e824fSDouglas Anderson 1748a28e824fSDouglas Anderson return 0; 1749a28e824fSDouglas Anderson } 1750a28e824fSDouglas Anderson EXPORT_SYMBOL_GPL(nvmem_cell_read_variable_le_u64); 1751a28e824fSDouglas Anderson 17528b977c54SYangtao Li /** 1753e2a5402eSSrinivas Kandagatla * nvmem_device_cell_read() - Read a given nvmem device and cell 1754e2a5402eSSrinivas Kandagatla * 1755e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to read from. 1756e2a5402eSSrinivas Kandagatla * @info: nvmem cell info to be read. 1757e2a5402eSSrinivas Kandagatla * @buf: buffer pointer which will be populated on successful read. 1758e2a5402eSSrinivas Kandagatla * 1759e2a5402eSSrinivas Kandagatla * Return: length of successful bytes read on success and negative 1760e2a5402eSSrinivas Kandagatla * error code on error. 1761e2a5402eSSrinivas Kandagatla */ 1762e2a5402eSSrinivas Kandagatla ssize_t nvmem_device_cell_read(struct nvmem_device *nvmem, 1763e2a5402eSSrinivas Kandagatla struct nvmem_cell_info *info, void *buf) 1764e2a5402eSSrinivas Kandagatla { 17657ae6478bSSrinivas Kandagatla struct nvmem_cell_entry cell; 1766e2a5402eSSrinivas Kandagatla int rc; 1767e2a5402eSSrinivas Kandagatla ssize_t len; 1768e2a5402eSSrinivas Kandagatla 1769795ddd18SSrinivas Kandagatla if (!nvmem) 1770e2a5402eSSrinivas Kandagatla return -EINVAL; 1771e2a5402eSSrinivas Kandagatla 17727ae6478bSSrinivas Kandagatla rc = nvmem_cell_info_to_nvmem_cell_entry_nodup(nvmem, info, &cell); 1773287980e4SArnd Bergmann if (rc) 1774e2a5402eSSrinivas Kandagatla return rc; 1775e2a5402eSSrinivas Kandagatla 17767ae6478bSSrinivas Kandagatla rc = __nvmem_cell_read(nvmem, &cell, buf, &len, NULL); 1777287980e4SArnd Bergmann if (rc) 1778e2a5402eSSrinivas Kandagatla return rc; 1779e2a5402eSSrinivas Kandagatla 1780e2a5402eSSrinivas Kandagatla return len; 1781e2a5402eSSrinivas Kandagatla } 1782e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_cell_read); 1783e2a5402eSSrinivas Kandagatla 1784e2a5402eSSrinivas Kandagatla /** 1785e2a5402eSSrinivas Kandagatla * nvmem_device_cell_write() - Write cell to a given nvmem device 1786e2a5402eSSrinivas Kandagatla * 1787e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to be written to. 178829143268SVivek Gautam * @info: nvmem cell info to be written. 1789e2a5402eSSrinivas Kandagatla * @buf: buffer to be written to cell. 1790e2a5402eSSrinivas Kandagatla * 1791e2a5402eSSrinivas Kandagatla * Return: length of bytes written or negative error code on failure. 179248f63a2cSBartosz Golaszewski */ 1793e2a5402eSSrinivas Kandagatla int nvmem_device_cell_write(struct nvmem_device *nvmem, 1794e2a5402eSSrinivas Kandagatla struct nvmem_cell_info *info, void *buf) 1795e2a5402eSSrinivas Kandagatla { 17967ae6478bSSrinivas Kandagatla struct nvmem_cell_entry cell; 1797e2a5402eSSrinivas Kandagatla int rc; 1798e2a5402eSSrinivas Kandagatla 1799795ddd18SSrinivas Kandagatla if (!nvmem) 1800e2a5402eSSrinivas Kandagatla return -EINVAL; 1801e2a5402eSSrinivas Kandagatla 18027ae6478bSSrinivas Kandagatla rc = nvmem_cell_info_to_nvmem_cell_entry_nodup(nvmem, info, &cell); 1803287980e4SArnd Bergmann if (rc) 1804e2a5402eSSrinivas Kandagatla return rc; 1805e2a5402eSSrinivas Kandagatla 18067ae6478bSSrinivas Kandagatla return __nvmem_cell_entry_write(&cell, buf, cell.bytes); 1807e2a5402eSSrinivas Kandagatla } 1808e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_cell_write); 1809e2a5402eSSrinivas Kandagatla 1810e2a5402eSSrinivas Kandagatla /** 1811e2a5402eSSrinivas Kandagatla * nvmem_device_read() - Read from a given nvmem device 1812e2a5402eSSrinivas Kandagatla * 1813e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to read from. 1814e2a5402eSSrinivas Kandagatla * @offset: offset in nvmem device. 1815e2a5402eSSrinivas Kandagatla * @bytes: number of bytes to read. 1816e2a5402eSSrinivas Kandagatla * @buf: buffer pointer which will be populated on successful read. 1817e2a5402eSSrinivas Kandagatla * 1818e2a5402eSSrinivas Kandagatla * Return: length of successful bytes read on success and negative 1819e2a5402eSSrinivas Kandagatla * error code on error. 1820e2a5402eSSrinivas Kandagatla */ 1821e2a5402eSSrinivas Kandagatla int nvmem_device_read(struct nvmem_device *nvmem, 1822e2a5402eSSrinivas Kandagatla unsigned int offset, 1823e2a5402eSSrinivas Kandagatla size_t bytes, void *buf) 1824e2a5402eSSrinivas Kandagatla { 1825e2a5402eSSrinivas Kandagatla int rc; 1826e2a5402eSSrinivas Kandagatla 1827795ddd18SSrinivas Kandagatla if (!nvmem) 1828e2a5402eSSrinivas Kandagatla return -EINVAL; 1829e2a5402eSSrinivas Kandagatla 1830795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, offset, buf, bytes); 1831e2a5402eSSrinivas Kandagatla 1832287980e4SArnd Bergmann if (rc) 1833e2a5402eSSrinivas Kandagatla return rc; 1834e2a5402eSSrinivas Kandagatla 1835e2a5402eSSrinivas Kandagatla return bytes; 1836e2a5402eSSrinivas Kandagatla } 1837e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_read); 1838e2a5402eSSrinivas Kandagatla 1839e2a5402eSSrinivas Kandagatla /** 1840e2a5402eSSrinivas Kandagatla * nvmem_device_write() - Write cell to a given nvmem device 1841e2a5402eSSrinivas Kandagatla * 1842e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to be written to. 1843e2a5402eSSrinivas Kandagatla * @offset: offset in nvmem device. 1844e2a5402eSSrinivas Kandagatla * @bytes: number of bytes to write. 1845e2a5402eSSrinivas Kandagatla * @buf: buffer to be written. 1846e2a5402eSSrinivas Kandagatla * 1847e2a5402eSSrinivas Kandagatla * Return: length of bytes written or negative error code on failure. 184848f63a2cSBartosz Golaszewski */ 1849e2a5402eSSrinivas Kandagatla int nvmem_device_write(struct nvmem_device *nvmem, 1850e2a5402eSSrinivas Kandagatla unsigned int offset, 1851e2a5402eSSrinivas Kandagatla size_t bytes, void *buf) 1852e2a5402eSSrinivas Kandagatla { 1853e2a5402eSSrinivas Kandagatla int rc; 1854e2a5402eSSrinivas Kandagatla 1855795ddd18SSrinivas Kandagatla if (!nvmem) 1856e2a5402eSSrinivas Kandagatla return -EINVAL; 1857e2a5402eSSrinivas Kandagatla 1858795ddd18SSrinivas Kandagatla rc = nvmem_reg_write(nvmem, offset, buf, bytes); 1859e2a5402eSSrinivas Kandagatla 1860287980e4SArnd Bergmann if (rc) 1861e2a5402eSSrinivas Kandagatla return rc; 1862e2a5402eSSrinivas Kandagatla 1863e2a5402eSSrinivas Kandagatla 1864e2a5402eSSrinivas Kandagatla return bytes; 1865e2a5402eSSrinivas Kandagatla } 1866e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_write); 1867e2a5402eSSrinivas Kandagatla 1868d7b9fd16SBartosz Golaszewski /** 1869b985f4cbSBartosz Golaszewski * nvmem_add_cell_table() - register a table of cell info entries 1870b985f4cbSBartosz Golaszewski * 1871b985f4cbSBartosz Golaszewski * @table: table of cell info entries 1872b985f4cbSBartosz Golaszewski */ 1873b985f4cbSBartosz Golaszewski void nvmem_add_cell_table(struct nvmem_cell_table *table) 1874b985f4cbSBartosz Golaszewski { 1875b985f4cbSBartosz Golaszewski mutex_lock(&nvmem_cell_mutex); 1876b985f4cbSBartosz Golaszewski list_add_tail(&table->node, &nvmem_cell_tables); 1877b985f4cbSBartosz Golaszewski mutex_unlock(&nvmem_cell_mutex); 1878b985f4cbSBartosz Golaszewski } 1879b985f4cbSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_add_cell_table); 1880b985f4cbSBartosz Golaszewski 1881b985f4cbSBartosz Golaszewski /** 1882b985f4cbSBartosz Golaszewski * nvmem_del_cell_table() - remove a previously registered cell info table 1883b985f4cbSBartosz Golaszewski * 1884b985f4cbSBartosz Golaszewski * @table: table of cell info entries 1885b985f4cbSBartosz Golaszewski */ 1886b985f4cbSBartosz Golaszewski void nvmem_del_cell_table(struct nvmem_cell_table *table) 1887b985f4cbSBartosz Golaszewski { 1888b985f4cbSBartosz Golaszewski mutex_lock(&nvmem_cell_mutex); 1889b985f4cbSBartosz Golaszewski list_del(&table->node); 1890b985f4cbSBartosz Golaszewski mutex_unlock(&nvmem_cell_mutex); 1891b985f4cbSBartosz Golaszewski } 1892b985f4cbSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_del_cell_table); 1893b985f4cbSBartosz Golaszewski 1894b985f4cbSBartosz Golaszewski /** 1895506157beSBartosz Golaszewski * nvmem_add_cell_lookups() - register a list of cell lookup entries 1896506157beSBartosz Golaszewski * 1897506157beSBartosz Golaszewski * @entries: array of cell lookup entries 1898506157beSBartosz Golaszewski * @nentries: number of cell lookup entries in the array 1899506157beSBartosz Golaszewski */ 1900506157beSBartosz Golaszewski void nvmem_add_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries) 1901506157beSBartosz Golaszewski { 1902506157beSBartosz Golaszewski int i; 1903506157beSBartosz Golaszewski 1904506157beSBartosz Golaszewski mutex_lock(&nvmem_lookup_mutex); 1905506157beSBartosz Golaszewski for (i = 0; i < nentries; i++) 1906506157beSBartosz Golaszewski list_add_tail(&entries[i].node, &nvmem_lookup_list); 1907506157beSBartosz Golaszewski mutex_unlock(&nvmem_lookup_mutex); 1908506157beSBartosz Golaszewski } 1909506157beSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_add_cell_lookups); 1910506157beSBartosz Golaszewski 1911506157beSBartosz Golaszewski /** 1912506157beSBartosz Golaszewski * nvmem_del_cell_lookups() - remove a list of previously added cell lookup 1913506157beSBartosz Golaszewski * entries 1914506157beSBartosz Golaszewski * 1915506157beSBartosz Golaszewski * @entries: array of cell lookup entries 1916506157beSBartosz Golaszewski * @nentries: number of cell lookup entries in the array 1917506157beSBartosz Golaszewski */ 1918506157beSBartosz Golaszewski void nvmem_del_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries) 1919506157beSBartosz Golaszewski { 1920506157beSBartosz Golaszewski int i; 1921506157beSBartosz Golaszewski 1922506157beSBartosz Golaszewski mutex_lock(&nvmem_lookup_mutex); 1923506157beSBartosz Golaszewski for (i = 0; i < nentries; i++) 1924506157beSBartosz Golaszewski list_del(&entries[i].node); 1925506157beSBartosz Golaszewski mutex_unlock(&nvmem_lookup_mutex); 1926506157beSBartosz Golaszewski } 1927506157beSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_del_cell_lookups); 1928506157beSBartosz Golaszewski 1929506157beSBartosz Golaszewski /** 1930d7b9fd16SBartosz Golaszewski * nvmem_dev_name() - Get the name of a given nvmem device. 1931d7b9fd16SBartosz Golaszewski * 1932d7b9fd16SBartosz Golaszewski * @nvmem: nvmem device. 1933d7b9fd16SBartosz Golaszewski * 1934d7b9fd16SBartosz Golaszewski * Return: name of the nvmem device. 1935d7b9fd16SBartosz Golaszewski */ 1936d7b9fd16SBartosz Golaszewski const char *nvmem_dev_name(struct nvmem_device *nvmem) 1937d7b9fd16SBartosz Golaszewski { 1938d7b9fd16SBartosz Golaszewski return dev_name(&nvmem->dev); 1939d7b9fd16SBartosz Golaszewski } 1940d7b9fd16SBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_dev_name); 1941d7b9fd16SBartosz Golaszewski 1942eace75cfSSrinivas Kandagatla static int __init nvmem_init(void) 1943eace75cfSSrinivas Kandagatla { 1944eace75cfSSrinivas Kandagatla return bus_register(&nvmem_bus_type); 1945eace75cfSSrinivas Kandagatla } 1946eace75cfSSrinivas Kandagatla 1947eace75cfSSrinivas Kandagatla static void __exit nvmem_exit(void) 1948eace75cfSSrinivas Kandagatla { 1949eace75cfSSrinivas Kandagatla bus_unregister(&nvmem_bus_type); 1950eace75cfSSrinivas Kandagatla } 1951eace75cfSSrinivas Kandagatla 1952eace75cfSSrinivas Kandagatla subsys_initcall(nvmem_init); 1953eace75cfSSrinivas Kandagatla module_exit(nvmem_exit); 1954eace75cfSSrinivas Kandagatla 1955eace75cfSSrinivas Kandagatla MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org"); 1956eace75cfSSrinivas Kandagatla MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com"); 1957eace75cfSSrinivas Kandagatla MODULE_DESCRIPTION("nvmem Driver Core"); 1958eace75cfSSrinivas Kandagatla MODULE_LICENSE("GPL v2"); 1959