1b1c1db98SBartosz Golaszewski // SPDX-License-Identifier: GPL-2.0 2eace75cfSSrinivas Kandagatla /* 3eace75cfSSrinivas Kandagatla * nvmem framework core. 4eace75cfSSrinivas Kandagatla * 5eace75cfSSrinivas Kandagatla * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org> 6eace75cfSSrinivas Kandagatla * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com> 7eace75cfSSrinivas Kandagatla */ 8eace75cfSSrinivas Kandagatla 9eace75cfSSrinivas Kandagatla #include <linux/device.h> 10eace75cfSSrinivas Kandagatla #include <linux/export.h> 11eace75cfSSrinivas Kandagatla #include <linux/fs.h> 12eace75cfSSrinivas Kandagatla #include <linux/idr.h> 13eace75cfSSrinivas Kandagatla #include <linux/init.h> 14c1de7f43SBartosz Golaszewski #include <linux/kref.h> 15eace75cfSSrinivas Kandagatla #include <linux/module.h> 16eace75cfSSrinivas Kandagatla #include <linux/nvmem-consumer.h> 17eace75cfSSrinivas Kandagatla #include <linux/nvmem-provider.h> 182a127da4SKhouloud Touil #include <linux/gpio/consumer.h> 19eace75cfSSrinivas Kandagatla #include <linux/of.h> 20eace75cfSSrinivas Kandagatla #include <linux/slab.h> 2184400305SSrinivas Kandagatla 2284400305SSrinivas Kandagatla struct nvmem_device { 2384400305SSrinivas Kandagatla struct module *owner; 2484400305SSrinivas Kandagatla struct device dev; 2584400305SSrinivas Kandagatla int stride; 2684400305SSrinivas Kandagatla int word_size; 2784400305SSrinivas Kandagatla int id; 2884400305SSrinivas Kandagatla struct kref refcnt; 2984400305SSrinivas Kandagatla size_t size; 3084400305SSrinivas Kandagatla bool read_only; 3184400305SSrinivas Kandagatla bool root_only; 3284400305SSrinivas Kandagatla int flags; 3384400305SSrinivas Kandagatla enum nvmem_type type; 3484400305SSrinivas Kandagatla struct bin_attribute eeprom; 3584400305SSrinivas Kandagatla struct device *base_dev; 3684400305SSrinivas Kandagatla struct list_head cells; 37fd3bb8f5SEvan Green const struct nvmem_keepout *keepout; 38fd3bb8f5SEvan Green unsigned int nkeepout; 3984400305SSrinivas Kandagatla nvmem_reg_read_t reg_read; 4084400305SSrinivas Kandagatla nvmem_reg_write_t reg_write; 4184400305SSrinivas Kandagatla struct gpio_desc *wp_gpio; 4284400305SSrinivas Kandagatla void *priv; 4384400305SSrinivas Kandagatla }; 4484400305SSrinivas Kandagatla 4584400305SSrinivas Kandagatla #define to_nvmem_device(d) container_of(d, struct nvmem_device, dev) 4684400305SSrinivas Kandagatla 4784400305SSrinivas Kandagatla #define FLAG_COMPAT BIT(0) 48b6c217abSAndrew Lunn 49eace75cfSSrinivas Kandagatla struct nvmem_cell { 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 60eace75cfSSrinivas Kandagatla static DEFINE_MUTEX(nvmem_mutex); 61eace75cfSSrinivas Kandagatla static DEFINE_IDA(nvmem_ida); 62eace75cfSSrinivas Kandagatla 63b985f4cbSBartosz Golaszewski static DEFINE_MUTEX(nvmem_cell_mutex); 64b985f4cbSBartosz Golaszewski static LIST_HEAD(nvmem_cell_tables); 65b985f4cbSBartosz Golaszewski 66506157beSBartosz Golaszewski static DEFINE_MUTEX(nvmem_lookup_mutex); 67506157beSBartosz Golaszewski static LIST_HEAD(nvmem_lookup_list); 68506157beSBartosz Golaszewski 69bee1138bSBartosz Golaszewski static BLOCKING_NOTIFIER_HEAD(nvmem_notifier); 70bee1138bSBartosz Golaszewski 71fd3bb8f5SEvan Green static int __nvmem_reg_read(struct nvmem_device *nvmem, unsigned int offset, 72b96fc541SMichael Auchter void *val, size_t bytes) 73b96fc541SMichael Auchter { 74b96fc541SMichael Auchter if (nvmem->reg_read) 75b96fc541SMichael Auchter return nvmem->reg_read(nvmem->priv, offset, val, bytes); 76b96fc541SMichael Auchter 77b96fc541SMichael Auchter return -EINVAL; 78b96fc541SMichael Auchter } 79b96fc541SMichael Auchter 80fd3bb8f5SEvan Green static int __nvmem_reg_write(struct nvmem_device *nvmem, unsigned int offset, 81b96fc541SMichael Auchter void *val, size_t bytes) 82b96fc541SMichael Auchter { 83b96fc541SMichael Auchter int ret; 84b96fc541SMichael Auchter 85b96fc541SMichael Auchter if (nvmem->reg_write) { 86b96fc541SMichael Auchter gpiod_set_value_cansleep(nvmem->wp_gpio, 0); 87b96fc541SMichael Auchter ret = nvmem->reg_write(nvmem->priv, offset, val, bytes); 88b96fc541SMichael Auchter gpiod_set_value_cansleep(nvmem->wp_gpio, 1); 89b96fc541SMichael Auchter return ret; 90b96fc541SMichael Auchter } 91b96fc541SMichael Auchter 92b96fc541SMichael Auchter return -EINVAL; 93b96fc541SMichael Auchter } 94b96fc541SMichael Auchter 95fd3bb8f5SEvan Green static int nvmem_access_with_keepouts(struct nvmem_device *nvmem, 96fd3bb8f5SEvan Green unsigned int offset, void *val, 97fd3bb8f5SEvan Green size_t bytes, int write) 98fd3bb8f5SEvan Green { 99fd3bb8f5SEvan Green 100fd3bb8f5SEvan Green unsigned int end = offset + bytes; 101fd3bb8f5SEvan Green unsigned int kend, ksize; 102fd3bb8f5SEvan Green const struct nvmem_keepout *keepout = nvmem->keepout; 103fd3bb8f5SEvan Green const struct nvmem_keepout *keepoutend = keepout + nvmem->nkeepout; 104fd3bb8f5SEvan Green int rc; 105fd3bb8f5SEvan Green 106fd3bb8f5SEvan Green /* 107fd3bb8f5SEvan Green * Skip all keepouts before the range being accessed. 108fd3bb8f5SEvan Green * Keepouts are sorted. 109fd3bb8f5SEvan Green */ 110fd3bb8f5SEvan Green while ((keepout < keepoutend) && (keepout->end <= offset)) 111fd3bb8f5SEvan Green keepout++; 112fd3bb8f5SEvan Green 113fd3bb8f5SEvan Green while ((offset < end) && (keepout < keepoutend)) { 114fd3bb8f5SEvan Green /* Access the valid portion before the keepout. */ 115fd3bb8f5SEvan Green if (offset < keepout->start) { 116fd3bb8f5SEvan Green kend = min(end, keepout->start); 117fd3bb8f5SEvan Green ksize = kend - offset; 118fd3bb8f5SEvan Green if (write) 119fd3bb8f5SEvan Green rc = __nvmem_reg_write(nvmem, offset, val, ksize); 120fd3bb8f5SEvan Green else 121fd3bb8f5SEvan Green rc = __nvmem_reg_read(nvmem, offset, val, ksize); 122fd3bb8f5SEvan Green 123fd3bb8f5SEvan Green if (rc) 124fd3bb8f5SEvan Green return rc; 125fd3bb8f5SEvan Green 126fd3bb8f5SEvan Green offset += ksize; 127fd3bb8f5SEvan Green val += ksize; 128fd3bb8f5SEvan Green } 129fd3bb8f5SEvan Green 130fd3bb8f5SEvan Green /* 131fd3bb8f5SEvan Green * Now we're aligned to the start of this keepout zone. Go 132fd3bb8f5SEvan Green * through it. 133fd3bb8f5SEvan Green */ 134fd3bb8f5SEvan Green kend = min(end, keepout->end); 135fd3bb8f5SEvan Green ksize = kend - offset; 136fd3bb8f5SEvan Green if (!write) 137fd3bb8f5SEvan Green memset(val, keepout->value, ksize); 138fd3bb8f5SEvan Green 139fd3bb8f5SEvan Green val += ksize; 140fd3bb8f5SEvan Green offset += ksize; 141fd3bb8f5SEvan Green keepout++; 142fd3bb8f5SEvan Green } 143fd3bb8f5SEvan Green 144fd3bb8f5SEvan Green /* 145fd3bb8f5SEvan Green * If we ran out of keepouts but there's still stuff to do, send it 146fd3bb8f5SEvan Green * down directly 147fd3bb8f5SEvan Green */ 148fd3bb8f5SEvan Green if (offset < end) { 149fd3bb8f5SEvan Green ksize = end - offset; 150fd3bb8f5SEvan Green if (write) 151fd3bb8f5SEvan Green return __nvmem_reg_write(nvmem, offset, val, ksize); 152fd3bb8f5SEvan Green else 153fd3bb8f5SEvan Green return __nvmem_reg_read(nvmem, offset, val, ksize); 154fd3bb8f5SEvan Green } 155fd3bb8f5SEvan Green 156fd3bb8f5SEvan Green return 0; 157fd3bb8f5SEvan Green } 158fd3bb8f5SEvan Green 159fd3bb8f5SEvan Green static int nvmem_reg_read(struct nvmem_device *nvmem, unsigned int offset, 160fd3bb8f5SEvan Green void *val, size_t bytes) 161fd3bb8f5SEvan Green { 162fd3bb8f5SEvan Green if (!nvmem->nkeepout) 163fd3bb8f5SEvan Green return __nvmem_reg_read(nvmem, offset, val, bytes); 164fd3bb8f5SEvan Green 165fd3bb8f5SEvan Green return nvmem_access_with_keepouts(nvmem, offset, val, bytes, false); 166fd3bb8f5SEvan Green } 167fd3bb8f5SEvan Green 168fd3bb8f5SEvan Green static int nvmem_reg_write(struct nvmem_device *nvmem, unsigned int offset, 169fd3bb8f5SEvan Green void *val, size_t bytes) 170fd3bb8f5SEvan Green { 171fd3bb8f5SEvan Green if (!nvmem->nkeepout) 172fd3bb8f5SEvan Green return __nvmem_reg_write(nvmem, offset, val, bytes); 173fd3bb8f5SEvan Green 174fd3bb8f5SEvan Green return nvmem_access_with_keepouts(nvmem, offset, val, bytes, true); 175fd3bb8f5SEvan Green } 176fd3bb8f5SEvan Green 17784400305SSrinivas Kandagatla #ifdef CONFIG_NVMEM_SYSFS 17884400305SSrinivas Kandagatla static const char * const nvmem_type_str[] = { 17984400305SSrinivas Kandagatla [NVMEM_TYPE_UNKNOWN] = "Unknown", 18084400305SSrinivas Kandagatla [NVMEM_TYPE_EEPROM] = "EEPROM", 18184400305SSrinivas Kandagatla [NVMEM_TYPE_OTP] = "OTP", 18284400305SSrinivas Kandagatla [NVMEM_TYPE_BATTERY_BACKED] = "Battery backed", 18384400305SSrinivas Kandagatla }; 18484400305SSrinivas Kandagatla 18584400305SSrinivas Kandagatla #ifdef CONFIG_DEBUG_LOCK_ALLOC 18684400305SSrinivas Kandagatla static struct lock_class_key eeprom_lock_key; 18784400305SSrinivas Kandagatla #endif 18884400305SSrinivas Kandagatla 18984400305SSrinivas Kandagatla static ssize_t type_show(struct device *dev, 19084400305SSrinivas Kandagatla struct device_attribute *attr, char *buf) 19184400305SSrinivas Kandagatla { 19284400305SSrinivas Kandagatla struct nvmem_device *nvmem = to_nvmem_device(dev); 19384400305SSrinivas Kandagatla 19484400305SSrinivas Kandagatla return sprintf(buf, "%s\n", nvmem_type_str[nvmem->type]); 19584400305SSrinivas Kandagatla } 19684400305SSrinivas Kandagatla 19784400305SSrinivas Kandagatla static DEVICE_ATTR_RO(type); 19884400305SSrinivas Kandagatla 19984400305SSrinivas Kandagatla static struct attribute *nvmem_attrs[] = { 20084400305SSrinivas Kandagatla &dev_attr_type.attr, 20184400305SSrinivas Kandagatla NULL, 20284400305SSrinivas Kandagatla }; 20384400305SSrinivas Kandagatla 20484400305SSrinivas Kandagatla static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj, 20584400305SSrinivas Kandagatla struct bin_attribute *attr, char *buf, 20684400305SSrinivas Kandagatla loff_t pos, size_t count) 20784400305SSrinivas Kandagatla { 20884400305SSrinivas Kandagatla struct device *dev; 20984400305SSrinivas Kandagatla struct nvmem_device *nvmem; 21084400305SSrinivas Kandagatla int rc; 21184400305SSrinivas Kandagatla 21284400305SSrinivas Kandagatla if (attr->private) 21384400305SSrinivas Kandagatla dev = attr->private; 21484400305SSrinivas Kandagatla else 21528371cc6STian Tao dev = kobj_to_dev(kobj); 21684400305SSrinivas Kandagatla nvmem = to_nvmem_device(dev); 21784400305SSrinivas Kandagatla 21884400305SSrinivas Kandagatla /* Stop the user from reading */ 21984400305SSrinivas Kandagatla if (pos >= nvmem->size) 22084400305SSrinivas Kandagatla return 0; 22184400305SSrinivas Kandagatla 22283566715SDouglas Anderson if (!IS_ALIGNED(pos, nvmem->stride)) 22383566715SDouglas Anderson return -EINVAL; 22483566715SDouglas Anderson 22584400305SSrinivas Kandagatla if (count < nvmem->word_size) 22684400305SSrinivas Kandagatla return -EINVAL; 22784400305SSrinivas Kandagatla 22884400305SSrinivas Kandagatla if (pos + count > nvmem->size) 22984400305SSrinivas Kandagatla count = nvmem->size - pos; 23084400305SSrinivas Kandagatla 23184400305SSrinivas Kandagatla count = round_down(count, nvmem->word_size); 23284400305SSrinivas Kandagatla 23384400305SSrinivas Kandagatla if (!nvmem->reg_read) 23484400305SSrinivas Kandagatla return -EPERM; 23584400305SSrinivas Kandagatla 236b96fc541SMichael Auchter rc = nvmem_reg_read(nvmem, pos, buf, count); 23784400305SSrinivas Kandagatla 23884400305SSrinivas Kandagatla if (rc) 23984400305SSrinivas Kandagatla return rc; 24084400305SSrinivas Kandagatla 24184400305SSrinivas Kandagatla return count; 24284400305SSrinivas Kandagatla } 24384400305SSrinivas Kandagatla 24484400305SSrinivas Kandagatla static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj, 24584400305SSrinivas Kandagatla struct bin_attribute *attr, char *buf, 24684400305SSrinivas Kandagatla loff_t pos, size_t count) 24784400305SSrinivas Kandagatla { 24884400305SSrinivas Kandagatla struct device *dev; 24984400305SSrinivas Kandagatla struct nvmem_device *nvmem; 25084400305SSrinivas Kandagatla int rc; 25184400305SSrinivas Kandagatla 25284400305SSrinivas Kandagatla if (attr->private) 25384400305SSrinivas Kandagatla dev = attr->private; 25484400305SSrinivas Kandagatla else 25528371cc6STian Tao dev = kobj_to_dev(kobj); 25684400305SSrinivas Kandagatla nvmem = to_nvmem_device(dev); 25784400305SSrinivas Kandagatla 25884400305SSrinivas Kandagatla /* Stop the user from writing */ 25984400305SSrinivas Kandagatla if (pos >= nvmem->size) 26084400305SSrinivas Kandagatla return -EFBIG; 26184400305SSrinivas Kandagatla 26283566715SDouglas Anderson if (!IS_ALIGNED(pos, nvmem->stride)) 26383566715SDouglas Anderson return -EINVAL; 26483566715SDouglas Anderson 26584400305SSrinivas Kandagatla if (count < nvmem->word_size) 26684400305SSrinivas Kandagatla return -EINVAL; 26784400305SSrinivas Kandagatla 26884400305SSrinivas Kandagatla if (pos + count > nvmem->size) 26984400305SSrinivas Kandagatla count = nvmem->size - pos; 27084400305SSrinivas Kandagatla 27184400305SSrinivas Kandagatla count = round_down(count, nvmem->word_size); 27284400305SSrinivas Kandagatla 27384400305SSrinivas Kandagatla if (!nvmem->reg_write) 27484400305SSrinivas Kandagatla return -EPERM; 27584400305SSrinivas Kandagatla 276b96fc541SMichael Auchter rc = nvmem_reg_write(nvmem, pos, buf, count); 27784400305SSrinivas Kandagatla 27884400305SSrinivas Kandagatla if (rc) 27984400305SSrinivas Kandagatla return rc; 28084400305SSrinivas Kandagatla 28184400305SSrinivas Kandagatla return count; 28284400305SSrinivas Kandagatla } 28384400305SSrinivas Kandagatla 2842a4542e5SSrinivas Kandagatla static umode_t nvmem_bin_attr_get_umode(struct nvmem_device *nvmem) 28584400305SSrinivas Kandagatla { 28684400305SSrinivas Kandagatla umode_t mode = 0400; 28784400305SSrinivas Kandagatla 28884400305SSrinivas Kandagatla if (!nvmem->root_only) 28984400305SSrinivas Kandagatla mode |= 0044; 29084400305SSrinivas Kandagatla 29184400305SSrinivas Kandagatla if (!nvmem->read_only) 29284400305SSrinivas Kandagatla mode |= 0200; 29384400305SSrinivas Kandagatla 29484400305SSrinivas Kandagatla if (!nvmem->reg_write) 29584400305SSrinivas Kandagatla mode &= ~0200; 29684400305SSrinivas Kandagatla 29784400305SSrinivas Kandagatla if (!nvmem->reg_read) 29884400305SSrinivas Kandagatla mode &= ~0444; 29984400305SSrinivas Kandagatla 30084400305SSrinivas Kandagatla return mode; 30184400305SSrinivas Kandagatla } 30284400305SSrinivas Kandagatla 3032a4542e5SSrinivas Kandagatla static umode_t nvmem_bin_attr_is_visible(struct kobject *kobj, 3042a4542e5SSrinivas Kandagatla struct bin_attribute *attr, int i) 3052a4542e5SSrinivas Kandagatla { 30628371cc6STian Tao struct device *dev = kobj_to_dev(kobj); 3072a4542e5SSrinivas Kandagatla struct nvmem_device *nvmem = to_nvmem_device(dev); 3082a4542e5SSrinivas Kandagatla 3092a4542e5SSrinivas Kandagatla return nvmem_bin_attr_get_umode(nvmem); 3102a4542e5SSrinivas Kandagatla } 3112a4542e5SSrinivas Kandagatla 31284400305SSrinivas Kandagatla /* default read/write permissions */ 31384400305SSrinivas Kandagatla static struct bin_attribute bin_attr_rw_nvmem = { 31484400305SSrinivas Kandagatla .attr = { 31584400305SSrinivas Kandagatla .name = "nvmem", 31684400305SSrinivas Kandagatla .mode = 0644, 31784400305SSrinivas Kandagatla }, 31884400305SSrinivas Kandagatla .read = bin_attr_nvmem_read, 31984400305SSrinivas Kandagatla .write = bin_attr_nvmem_write, 32084400305SSrinivas Kandagatla }; 32184400305SSrinivas Kandagatla 32284400305SSrinivas Kandagatla static struct bin_attribute *nvmem_bin_attributes[] = { 32384400305SSrinivas Kandagatla &bin_attr_rw_nvmem, 32484400305SSrinivas Kandagatla NULL, 32584400305SSrinivas Kandagatla }; 32684400305SSrinivas Kandagatla 32784400305SSrinivas Kandagatla static const struct attribute_group nvmem_bin_group = { 32884400305SSrinivas Kandagatla .bin_attrs = nvmem_bin_attributes, 32984400305SSrinivas Kandagatla .attrs = nvmem_attrs, 33084400305SSrinivas Kandagatla .is_bin_visible = nvmem_bin_attr_is_visible, 33184400305SSrinivas Kandagatla }; 33284400305SSrinivas Kandagatla 33384400305SSrinivas Kandagatla static const struct attribute_group *nvmem_dev_groups[] = { 33484400305SSrinivas Kandagatla &nvmem_bin_group, 33584400305SSrinivas Kandagatla NULL, 33684400305SSrinivas Kandagatla }; 33784400305SSrinivas Kandagatla 3382a4542e5SSrinivas Kandagatla static struct bin_attribute bin_attr_nvmem_eeprom_compat = { 33984400305SSrinivas Kandagatla .attr = { 3402a4542e5SSrinivas Kandagatla .name = "eeprom", 34184400305SSrinivas Kandagatla }, 34284400305SSrinivas Kandagatla .read = bin_attr_nvmem_read, 34384400305SSrinivas Kandagatla .write = bin_attr_nvmem_write, 34484400305SSrinivas Kandagatla }; 34584400305SSrinivas Kandagatla 34684400305SSrinivas Kandagatla /* 34784400305SSrinivas Kandagatla * nvmem_setup_compat() - Create an additional binary entry in 34884400305SSrinivas Kandagatla * drivers sys directory, to be backwards compatible with the older 34984400305SSrinivas Kandagatla * drivers/misc/eeprom drivers. 35084400305SSrinivas Kandagatla */ 35184400305SSrinivas Kandagatla static int nvmem_sysfs_setup_compat(struct nvmem_device *nvmem, 35284400305SSrinivas Kandagatla const struct nvmem_config *config) 35384400305SSrinivas Kandagatla { 35484400305SSrinivas Kandagatla int rval; 35584400305SSrinivas Kandagatla 35684400305SSrinivas Kandagatla if (!config->compat) 35784400305SSrinivas Kandagatla return 0; 35884400305SSrinivas Kandagatla 35984400305SSrinivas Kandagatla if (!config->base_dev) 36084400305SSrinivas Kandagatla return -EINVAL; 36184400305SSrinivas Kandagatla 3622a4542e5SSrinivas Kandagatla nvmem->eeprom = bin_attr_nvmem_eeprom_compat; 3632a4542e5SSrinivas Kandagatla nvmem->eeprom.attr.mode = nvmem_bin_attr_get_umode(nvmem); 36484400305SSrinivas Kandagatla nvmem->eeprom.size = nvmem->size; 36584400305SSrinivas Kandagatla #ifdef CONFIG_DEBUG_LOCK_ALLOC 36684400305SSrinivas Kandagatla nvmem->eeprom.attr.key = &eeprom_lock_key; 36784400305SSrinivas Kandagatla #endif 36884400305SSrinivas Kandagatla nvmem->eeprom.private = &nvmem->dev; 36984400305SSrinivas Kandagatla nvmem->base_dev = config->base_dev; 37084400305SSrinivas Kandagatla 37184400305SSrinivas Kandagatla rval = device_create_bin_file(nvmem->base_dev, &nvmem->eeprom); 37284400305SSrinivas Kandagatla if (rval) { 37384400305SSrinivas Kandagatla dev_err(&nvmem->dev, 37484400305SSrinivas Kandagatla "Failed to create eeprom binary file %d\n", rval); 37584400305SSrinivas Kandagatla return rval; 37684400305SSrinivas Kandagatla } 37784400305SSrinivas Kandagatla 37884400305SSrinivas Kandagatla nvmem->flags |= FLAG_COMPAT; 37984400305SSrinivas Kandagatla 38084400305SSrinivas Kandagatla return 0; 38184400305SSrinivas Kandagatla } 38284400305SSrinivas Kandagatla 38384400305SSrinivas Kandagatla static void nvmem_sysfs_remove_compat(struct nvmem_device *nvmem, 38484400305SSrinivas Kandagatla const struct nvmem_config *config) 38584400305SSrinivas Kandagatla { 38684400305SSrinivas Kandagatla if (config->compat) 38784400305SSrinivas Kandagatla device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); 38884400305SSrinivas Kandagatla } 38984400305SSrinivas Kandagatla 39084400305SSrinivas Kandagatla #else /* CONFIG_NVMEM_SYSFS */ 39184400305SSrinivas Kandagatla 39284400305SSrinivas Kandagatla static int nvmem_sysfs_setup_compat(struct nvmem_device *nvmem, 39384400305SSrinivas Kandagatla const struct nvmem_config *config) 39484400305SSrinivas Kandagatla { 39584400305SSrinivas Kandagatla return -ENOSYS; 39684400305SSrinivas Kandagatla } 39784400305SSrinivas Kandagatla static void nvmem_sysfs_remove_compat(struct nvmem_device *nvmem, 39884400305SSrinivas Kandagatla const struct nvmem_config *config) 39984400305SSrinivas Kandagatla { 40084400305SSrinivas Kandagatla } 40184400305SSrinivas Kandagatla 40284400305SSrinivas Kandagatla #endif /* CONFIG_NVMEM_SYSFS */ 403a8b44d5dSAndy Shevchenko 404eace75cfSSrinivas Kandagatla static void nvmem_release(struct device *dev) 405eace75cfSSrinivas Kandagatla { 406eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem = to_nvmem_device(dev); 407eace75cfSSrinivas Kandagatla 4081eb51d6aSBartosz Golaszewski ida_free(&nvmem_ida, nvmem->id); 409a9c3766cSKhouloud Touil gpiod_put(nvmem->wp_gpio); 410eace75cfSSrinivas Kandagatla kfree(nvmem); 411eace75cfSSrinivas Kandagatla } 412eace75cfSSrinivas Kandagatla 413eace75cfSSrinivas Kandagatla static const struct device_type nvmem_provider_type = { 414eace75cfSSrinivas Kandagatla .release = nvmem_release, 415eace75cfSSrinivas Kandagatla }; 416eace75cfSSrinivas Kandagatla 417eace75cfSSrinivas Kandagatla static struct bus_type nvmem_bus_type = { 418eace75cfSSrinivas Kandagatla .name = "nvmem", 419eace75cfSSrinivas Kandagatla }; 420eace75cfSSrinivas Kandagatla 421eace75cfSSrinivas Kandagatla static void nvmem_cell_drop(struct nvmem_cell *cell) 422eace75cfSSrinivas Kandagatla { 423bee1138bSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_REMOVE, cell); 424c7235ee3SBartosz Golaszewski mutex_lock(&nvmem_mutex); 425eace75cfSSrinivas Kandagatla list_del(&cell->node); 426c7235ee3SBartosz Golaszewski mutex_unlock(&nvmem_mutex); 4270749aa25SSrinivas Kandagatla of_node_put(cell->np); 42816bb7abcSBitan Biswas kfree_const(cell->name); 429eace75cfSSrinivas Kandagatla kfree(cell); 430eace75cfSSrinivas Kandagatla } 431eace75cfSSrinivas Kandagatla 432eace75cfSSrinivas Kandagatla static void nvmem_device_remove_all_cells(const struct nvmem_device *nvmem) 433eace75cfSSrinivas Kandagatla { 4341852183eSBartosz Golaszewski struct nvmem_cell *cell, *p; 435eace75cfSSrinivas Kandagatla 436c7235ee3SBartosz Golaszewski list_for_each_entry_safe(cell, p, &nvmem->cells, node) 437eace75cfSSrinivas Kandagatla nvmem_cell_drop(cell); 438eace75cfSSrinivas Kandagatla } 439eace75cfSSrinivas Kandagatla 440eace75cfSSrinivas Kandagatla static void nvmem_cell_add(struct nvmem_cell *cell) 441eace75cfSSrinivas Kandagatla { 442c7235ee3SBartosz Golaszewski mutex_lock(&nvmem_mutex); 443c7235ee3SBartosz Golaszewski list_add_tail(&cell->node, &cell->nvmem->cells); 444c7235ee3SBartosz Golaszewski mutex_unlock(&nvmem_mutex); 445bee1138bSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_ADD, cell); 446eace75cfSSrinivas Kandagatla } 447eace75cfSSrinivas Kandagatla 448fc9eec4dSVadym Kochan static int nvmem_cell_info_to_nvmem_cell_nodup(struct nvmem_device *nvmem, 449eace75cfSSrinivas Kandagatla const struct nvmem_cell_info *info, 450eace75cfSSrinivas Kandagatla struct nvmem_cell *cell) 451eace75cfSSrinivas Kandagatla { 452eace75cfSSrinivas Kandagatla cell->nvmem = nvmem; 453eace75cfSSrinivas Kandagatla cell->offset = info->offset; 454eace75cfSSrinivas Kandagatla cell->bytes = info->bytes; 455fc9eec4dSVadym Kochan cell->name = info->name; 456eace75cfSSrinivas Kandagatla 457eace75cfSSrinivas Kandagatla cell->bit_offset = info->bit_offset; 458eace75cfSSrinivas Kandagatla cell->nbits = info->nbits; 459eace75cfSSrinivas Kandagatla 460eace75cfSSrinivas Kandagatla if (cell->nbits) 461eace75cfSSrinivas Kandagatla cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset, 462eace75cfSSrinivas Kandagatla BITS_PER_BYTE); 463eace75cfSSrinivas Kandagatla 464eace75cfSSrinivas Kandagatla if (!IS_ALIGNED(cell->offset, nvmem->stride)) { 465eace75cfSSrinivas Kandagatla dev_err(&nvmem->dev, 466eace75cfSSrinivas Kandagatla "cell %s unaligned to nvmem stride %d\n", 467fc9eec4dSVadym Kochan cell->name ?: "<unknown>", nvmem->stride); 468eace75cfSSrinivas Kandagatla return -EINVAL; 469eace75cfSSrinivas Kandagatla } 470eace75cfSSrinivas Kandagatla 471eace75cfSSrinivas Kandagatla return 0; 472eace75cfSSrinivas Kandagatla } 473eace75cfSSrinivas Kandagatla 474fc9eec4dSVadym Kochan static int nvmem_cell_info_to_nvmem_cell(struct nvmem_device *nvmem, 475fc9eec4dSVadym Kochan const struct nvmem_cell_info *info, 476fc9eec4dSVadym Kochan struct nvmem_cell *cell) 477fc9eec4dSVadym Kochan { 478fc9eec4dSVadym Kochan int err; 479fc9eec4dSVadym Kochan 480fc9eec4dSVadym Kochan err = nvmem_cell_info_to_nvmem_cell_nodup(nvmem, info, cell); 481fc9eec4dSVadym Kochan if (err) 482fc9eec4dSVadym Kochan return err; 483fc9eec4dSVadym Kochan 484fc9eec4dSVadym Kochan cell->name = kstrdup_const(info->name, GFP_KERNEL); 485fc9eec4dSVadym Kochan if (!cell->name) 486fc9eec4dSVadym Kochan return -ENOMEM; 487fc9eec4dSVadym Kochan 488fc9eec4dSVadym Kochan return 0; 489fc9eec4dSVadym Kochan } 490fc9eec4dSVadym Kochan 491b3db17e4SAndrew Lunn /** 492b3db17e4SAndrew Lunn * nvmem_add_cells() - Add cell information to an nvmem device 493b3db17e4SAndrew Lunn * 494b3db17e4SAndrew Lunn * @nvmem: nvmem device to add cells to. 495b3db17e4SAndrew Lunn * @info: nvmem cell info to add to the device 496b3db17e4SAndrew Lunn * @ncells: number of cells in info 497b3db17e4SAndrew Lunn * 498b3db17e4SAndrew Lunn * Return: 0 or negative error code on failure. 499b3db17e4SAndrew Lunn */ 500ef92ab30SSrinivas Kandagatla static int nvmem_add_cells(struct nvmem_device *nvmem, 501b3db17e4SAndrew Lunn const struct nvmem_cell_info *info, 502b3db17e4SAndrew Lunn int ncells) 503eace75cfSSrinivas Kandagatla { 504eace75cfSSrinivas Kandagatla struct nvmem_cell **cells; 505eace75cfSSrinivas Kandagatla int i, rval; 506eace75cfSSrinivas Kandagatla 507b3db17e4SAndrew Lunn cells = kcalloc(ncells, sizeof(*cells), GFP_KERNEL); 508eace75cfSSrinivas Kandagatla if (!cells) 509eace75cfSSrinivas Kandagatla return -ENOMEM; 510eace75cfSSrinivas Kandagatla 511b3db17e4SAndrew Lunn for (i = 0; i < ncells; i++) { 512eace75cfSSrinivas Kandagatla cells[i] = kzalloc(sizeof(**cells), GFP_KERNEL); 513eace75cfSSrinivas Kandagatla if (!cells[i]) { 514eace75cfSSrinivas Kandagatla rval = -ENOMEM; 515eace75cfSSrinivas Kandagatla goto err; 516eace75cfSSrinivas Kandagatla } 517eace75cfSSrinivas Kandagatla 518eace75cfSSrinivas Kandagatla rval = nvmem_cell_info_to_nvmem_cell(nvmem, &info[i], cells[i]); 519287980e4SArnd Bergmann if (rval) { 520eace75cfSSrinivas Kandagatla kfree(cells[i]); 521eace75cfSSrinivas Kandagatla goto err; 522eace75cfSSrinivas Kandagatla } 523eace75cfSSrinivas Kandagatla 524eace75cfSSrinivas Kandagatla nvmem_cell_add(cells[i]); 525eace75cfSSrinivas Kandagatla } 526eace75cfSSrinivas Kandagatla 527eace75cfSSrinivas Kandagatla /* remove tmp array */ 528eace75cfSSrinivas Kandagatla kfree(cells); 529eace75cfSSrinivas Kandagatla 530eace75cfSSrinivas Kandagatla return 0; 531eace75cfSSrinivas Kandagatla err: 532dfdf1414SRasmus Villemoes while (i--) 533eace75cfSSrinivas Kandagatla nvmem_cell_drop(cells[i]); 534eace75cfSSrinivas Kandagatla 535dfdf1414SRasmus Villemoes kfree(cells); 536dfdf1414SRasmus Villemoes 537eace75cfSSrinivas Kandagatla return rval; 538eace75cfSSrinivas Kandagatla } 539eace75cfSSrinivas Kandagatla 540bee1138bSBartosz Golaszewski /** 541bee1138bSBartosz Golaszewski * nvmem_register_notifier() - Register a notifier block for nvmem events. 542bee1138bSBartosz Golaszewski * 543bee1138bSBartosz Golaszewski * @nb: notifier block to be called on nvmem events. 544bee1138bSBartosz Golaszewski * 545bee1138bSBartosz Golaszewski * Return: 0 on success, negative error number on failure. 546bee1138bSBartosz Golaszewski */ 547bee1138bSBartosz Golaszewski int nvmem_register_notifier(struct notifier_block *nb) 548bee1138bSBartosz Golaszewski { 549bee1138bSBartosz Golaszewski return blocking_notifier_chain_register(&nvmem_notifier, nb); 550bee1138bSBartosz Golaszewski } 551bee1138bSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_register_notifier); 552bee1138bSBartosz Golaszewski 553bee1138bSBartosz Golaszewski /** 554bee1138bSBartosz Golaszewski * nvmem_unregister_notifier() - Unregister a notifier block for nvmem events. 555bee1138bSBartosz Golaszewski * 556bee1138bSBartosz Golaszewski * @nb: notifier block to be unregistered. 557bee1138bSBartosz Golaszewski * 558bee1138bSBartosz Golaszewski * Return: 0 on success, negative error number on failure. 559bee1138bSBartosz Golaszewski */ 560bee1138bSBartosz Golaszewski int nvmem_unregister_notifier(struct notifier_block *nb) 561bee1138bSBartosz Golaszewski { 562bee1138bSBartosz Golaszewski return blocking_notifier_chain_unregister(&nvmem_notifier, nb); 563bee1138bSBartosz Golaszewski } 564bee1138bSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_unregister_notifier); 565bee1138bSBartosz Golaszewski 566b985f4cbSBartosz Golaszewski static int nvmem_add_cells_from_table(struct nvmem_device *nvmem) 567b985f4cbSBartosz Golaszewski { 568b985f4cbSBartosz Golaszewski const struct nvmem_cell_info *info; 569b985f4cbSBartosz Golaszewski struct nvmem_cell_table *table; 570b985f4cbSBartosz Golaszewski struct nvmem_cell *cell; 571b985f4cbSBartosz Golaszewski int rval = 0, i; 572b985f4cbSBartosz Golaszewski 573b985f4cbSBartosz Golaszewski mutex_lock(&nvmem_cell_mutex); 574b985f4cbSBartosz Golaszewski list_for_each_entry(table, &nvmem_cell_tables, node) { 575b985f4cbSBartosz Golaszewski if (strcmp(nvmem_dev_name(nvmem), table->nvmem_name) == 0) { 576b985f4cbSBartosz Golaszewski for (i = 0; i < table->ncells; i++) { 577b985f4cbSBartosz Golaszewski info = &table->cells[i]; 578b985f4cbSBartosz Golaszewski 579b985f4cbSBartosz Golaszewski cell = kzalloc(sizeof(*cell), GFP_KERNEL); 580b985f4cbSBartosz Golaszewski if (!cell) { 581b985f4cbSBartosz Golaszewski rval = -ENOMEM; 582b985f4cbSBartosz Golaszewski goto out; 583b985f4cbSBartosz Golaszewski } 584b985f4cbSBartosz Golaszewski 585b985f4cbSBartosz Golaszewski rval = nvmem_cell_info_to_nvmem_cell(nvmem, 586b985f4cbSBartosz Golaszewski info, 587b985f4cbSBartosz Golaszewski cell); 588b985f4cbSBartosz Golaszewski if (rval) { 589b985f4cbSBartosz Golaszewski kfree(cell); 590b985f4cbSBartosz Golaszewski goto out; 591b985f4cbSBartosz Golaszewski } 592b985f4cbSBartosz Golaszewski 593b985f4cbSBartosz Golaszewski nvmem_cell_add(cell); 594b985f4cbSBartosz Golaszewski } 595b985f4cbSBartosz Golaszewski } 596b985f4cbSBartosz Golaszewski } 597b985f4cbSBartosz Golaszewski 598b985f4cbSBartosz Golaszewski out: 599b985f4cbSBartosz Golaszewski mutex_unlock(&nvmem_cell_mutex); 600b985f4cbSBartosz Golaszewski return rval; 601b985f4cbSBartosz Golaszewski } 602b985f4cbSBartosz Golaszewski 603e888d445SBartosz Golaszewski static struct nvmem_cell * 604506157beSBartosz Golaszewski nvmem_find_cell_by_name(struct nvmem_device *nvmem, const char *cell_id) 605506157beSBartosz Golaszewski { 6061c832674SAlban Bedel struct nvmem_cell *iter, *cell = NULL; 607506157beSBartosz Golaszewski 608506157beSBartosz Golaszewski mutex_lock(&nvmem_mutex); 6091c832674SAlban Bedel list_for_each_entry(iter, &nvmem->cells, node) { 6101c832674SAlban Bedel if (strcmp(cell_id, iter->name) == 0) { 6111c832674SAlban Bedel cell = iter; 612506157beSBartosz Golaszewski break; 613506157beSBartosz Golaszewski } 6141c832674SAlban Bedel } 615506157beSBartosz Golaszewski mutex_unlock(&nvmem_mutex); 616506157beSBartosz Golaszewski 617506157beSBartosz Golaszewski return cell; 618506157beSBartosz Golaszewski } 619506157beSBartosz Golaszewski 620fd3bb8f5SEvan Green static int nvmem_validate_keepouts(struct nvmem_device *nvmem) 621fd3bb8f5SEvan Green { 622fd3bb8f5SEvan Green unsigned int cur = 0; 623fd3bb8f5SEvan Green const struct nvmem_keepout *keepout = nvmem->keepout; 624fd3bb8f5SEvan Green const struct nvmem_keepout *keepoutend = keepout + nvmem->nkeepout; 625fd3bb8f5SEvan Green 626fd3bb8f5SEvan Green while (keepout < keepoutend) { 627fd3bb8f5SEvan Green /* Ensure keepouts are sorted and don't overlap. */ 628fd3bb8f5SEvan Green if (keepout->start < cur) { 629fd3bb8f5SEvan Green dev_err(&nvmem->dev, 630fd3bb8f5SEvan Green "Keepout regions aren't sorted or overlap.\n"); 631fd3bb8f5SEvan Green 632fd3bb8f5SEvan Green return -ERANGE; 633fd3bb8f5SEvan Green } 634fd3bb8f5SEvan Green 635fd3bb8f5SEvan Green if (keepout->end < keepout->start) { 636fd3bb8f5SEvan Green dev_err(&nvmem->dev, 637fd3bb8f5SEvan Green "Invalid keepout region.\n"); 638fd3bb8f5SEvan Green 639fd3bb8f5SEvan Green return -EINVAL; 640fd3bb8f5SEvan Green } 641fd3bb8f5SEvan Green 642fd3bb8f5SEvan Green /* 643fd3bb8f5SEvan Green * Validate keepouts (and holes between) don't violate 644fd3bb8f5SEvan Green * word_size constraints. 645fd3bb8f5SEvan Green */ 646fd3bb8f5SEvan Green if ((keepout->end - keepout->start < nvmem->word_size) || 647fd3bb8f5SEvan Green ((keepout->start != cur) && 648fd3bb8f5SEvan Green (keepout->start - cur < nvmem->word_size))) { 649fd3bb8f5SEvan Green 650fd3bb8f5SEvan Green dev_err(&nvmem->dev, 651fd3bb8f5SEvan Green "Keepout regions violate word_size constraints.\n"); 652fd3bb8f5SEvan Green 653fd3bb8f5SEvan Green return -ERANGE; 654fd3bb8f5SEvan Green } 655fd3bb8f5SEvan Green 656fd3bb8f5SEvan Green /* Validate keepouts don't violate stride (alignment). */ 657fd3bb8f5SEvan Green if (!IS_ALIGNED(keepout->start, nvmem->stride) || 658fd3bb8f5SEvan Green !IS_ALIGNED(keepout->end, nvmem->stride)) { 659fd3bb8f5SEvan Green 660fd3bb8f5SEvan Green dev_err(&nvmem->dev, 661fd3bb8f5SEvan Green "Keepout regions violate stride.\n"); 662fd3bb8f5SEvan Green 663fd3bb8f5SEvan Green return -EINVAL; 664fd3bb8f5SEvan Green } 665fd3bb8f5SEvan Green 666fd3bb8f5SEvan Green cur = keepout->end; 667fd3bb8f5SEvan Green keepout++; 668fd3bb8f5SEvan Green } 669fd3bb8f5SEvan Green 670fd3bb8f5SEvan Green return 0; 671fd3bb8f5SEvan Green } 672fd3bb8f5SEvan Green 673e888d445SBartosz Golaszewski static int nvmem_add_cells_from_of(struct nvmem_device *nvmem) 674e888d445SBartosz Golaszewski { 675e888d445SBartosz Golaszewski struct device_node *parent, *child; 676e888d445SBartosz Golaszewski struct device *dev = &nvmem->dev; 677e888d445SBartosz Golaszewski struct nvmem_cell *cell; 678e888d445SBartosz Golaszewski const __be32 *addr; 679e888d445SBartosz Golaszewski int len; 680e888d445SBartosz Golaszewski 681e888d445SBartosz Golaszewski parent = dev->of_node; 682e888d445SBartosz Golaszewski 683e888d445SBartosz Golaszewski for_each_child_of_node(parent, child) { 684e888d445SBartosz Golaszewski addr = of_get_property(child, "reg", &len); 6850445efacSAhmad Fatoum if (!addr) 6860445efacSAhmad Fatoum continue; 6870445efacSAhmad Fatoum if (len < 2 * sizeof(u32)) { 688e888d445SBartosz Golaszewski dev_err(dev, "nvmem: invalid reg on %pOF\n", child); 689e888d445SBartosz Golaszewski return -EINVAL; 690e888d445SBartosz Golaszewski } 691e888d445SBartosz Golaszewski 692e888d445SBartosz Golaszewski cell = kzalloc(sizeof(*cell), GFP_KERNEL); 693e888d445SBartosz Golaszewski if (!cell) 694e888d445SBartosz Golaszewski return -ENOMEM; 695e888d445SBartosz Golaszewski 696e888d445SBartosz Golaszewski cell->nvmem = nvmem; 6970749aa25SSrinivas Kandagatla cell->np = of_node_get(child); 698e888d445SBartosz Golaszewski cell->offset = be32_to_cpup(addr++); 699e888d445SBartosz Golaszewski cell->bytes = be32_to_cpup(addr); 700badcdff1SRob Herring cell->name = kasprintf(GFP_KERNEL, "%pOFn", child); 701e888d445SBartosz Golaszewski 702e888d445SBartosz Golaszewski addr = of_get_property(child, "bits", &len); 703e888d445SBartosz Golaszewski if (addr && len == (2 * sizeof(u32))) { 704e888d445SBartosz Golaszewski cell->bit_offset = be32_to_cpup(addr++); 705e888d445SBartosz Golaszewski cell->nbits = be32_to_cpup(addr); 706e888d445SBartosz Golaszewski } 707e888d445SBartosz Golaszewski 708e888d445SBartosz Golaszewski if (cell->nbits) 709e888d445SBartosz Golaszewski cell->bytes = DIV_ROUND_UP( 710e888d445SBartosz Golaszewski cell->nbits + cell->bit_offset, 711e888d445SBartosz Golaszewski BITS_PER_BYTE); 712e888d445SBartosz Golaszewski 713e888d445SBartosz Golaszewski if (!IS_ALIGNED(cell->offset, nvmem->stride)) { 714e888d445SBartosz Golaszewski dev_err(dev, "cell %s unaligned to nvmem stride %d\n", 715e888d445SBartosz Golaszewski cell->name, nvmem->stride); 716e888d445SBartosz Golaszewski /* Cells already added will be freed later. */ 71716bb7abcSBitan Biswas kfree_const(cell->name); 71872e008ceSDan Carpenter of_node_put(cell->np); 719e888d445SBartosz Golaszewski kfree(cell); 720e888d445SBartosz Golaszewski return -EINVAL; 721e888d445SBartosz Golaszewski } 722e888d445SBartosz Golaszewski 723e888d445SBartosz Golaszewski nvmem_cell_add(cell); 724e888d445SBartosz Golaszewski } 725e888d445SBartosz Golaszewski 726e888d445SBartosz Golaszewski return 0; 727e888d445SBartosz Golaszewski } 728e888d445SBartosz Golaszewski 729eace75cfSSrinivas Kandagatla /** 730eace75cfSSrinivas Kandagatla * nvmem_register() - Register a nvmem device for given nvmem_config. 7313a758071SAndreas Färber * Also creates a binary entry in /sys/bus/nvmem/devices/dev-name/nvmem 732eace75cfSSrinivas Kandagatla * 733eace75cfSSrinivas Kandagatla * @config: nvmem device configuration with which nvmem device is created. 734eace75cfSSrinivas Kandagatla * 735eace75cfSSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device 736eace75cfSSrinivas Kandagatla * on success. 737eace75cfSSrinivas Kandagatla */ 738eace75cfSSrinivas Kandagatla 739eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem_register(const struct nvmem_config *config) 740eace75cfSSrinivas Kandagatla { 741eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem; 742eace75cfSSrinivas Kandagatla int rval; 743eace75cfSSrinivas Kandagatla 744eace75cfSSrinivas Kandagatla if (!config->dev) 745eace75cfSSrinivas Kandagatla return ERR_PTR(-EINVAL); 746eace75cfSSrinivas Kandagatla 747061a320bSSrinivas Kandagatla if (!config->reg_read && !config->reg_write) 748061a320bSSrinivas Kandagatla return ERR_PTR(-EINVAL); 749061a320bSSrinivas Kandagatla 750eace75cfSSrinivas Kandagatla nvmem = kzalloc(sizeof(*nvmem), GFP_KERNEL); 751eace75cfSSrinivas Kandagatla if (!nvmem) 752eace75cfSSrinivas Kandagatla return ERR_PTR(-ENOMEM); 753eace75cfSSrinivas Kandagatla 7541eb51d6aSBartosz Golaszewski rval = ida_alloc(&nvmem_ida, GFP_KERNEL); 755eace75cfSSrinivas Kandagatla if (rval < 0) { 756eace75cfSSrinivas Kandagatla kfree(nvmem); 757eace75cfSSrinivas Kandagatla return ERR_PTR(rval); 758eace75cfSSrinivas Kandagatla } 75931c6ff51SBartosz Golaszewski 7602a127da4SKhouloud Touil if (config->wp_gpio) 7612a127da4SKhouloud Touil nvmem->wp_gpio = config->wp_gpio; 7622a127da4SKhouloud Touil else 7632a127da4SKhouloud Touil nvmem->wp_gpio = gpiod_get_optional(config->dev, "wp", 7642a127da4SKhouloud Touil GPIOD_OUT_HIGH); 765f7d8d7dcSBartosz Golaszewski if (IS_ERR(nvmem->wp_gpio)) { 7661eb51d6aSBartosz Golaszewski ida_free(&nvmem_ida, nvmem->id); 767f7d8d7dcSBartosz Golaszewski rval = PTR_ERR(nvmem->wp_gpio); 768f7d8d7dcSBartosz Golaszewski kfree(nvmem); 769f7d8d7dcSBartosz Golaszewski return ERR_PTR(rval); 770f7d8d7dcSBartosz Golaszewski } 7712a127da4SKhouloud Touil 772c1de7f43SBartosz Golaszewski kref_init(&nvmem->refcnt); 773c7235ee3SBartosz Golaszewski INIT_LIST_HEAD(&nvmem->cells); 774c1de7f43SBartosz Golaszewski 775eace75cfSSrinivas Kandagatla nvmem->id = rval; 776eace75cfSSrinivas Kandagatla nvmem->owner = config->owner; 77717eb18d6SMasahiro Yamada if (!nvmem->owner && config->dev->driver) 77817eb18d6SMasahiro Yamada nvmem->owner = config->dev->driver->owner; 77999897efdSHeiner Kallweit nvmem->stride = config->stride ?: 1; 78099897efdSHeiner Kallweit nvmem->word_size = config->word_size ?: 1; 781795ddd18SSrinivas Kandagatla nvmem->size = config->size; 782eace75cfSSrinivas Kandagatla nvmem->dev.type = &nvmem_provider_type; 783eace75cfSSrinivas Kandagatla nvmem->dev.bus = &nvmem_bus_type; 784eace75cfSSrinivas Kandagatla nvmem->dev.parent = config->dev; 785e6de179dSSrinivas Kandagatla nvmem->root_only = config->root_only; 786795ddd18SSrinivas Kandagatla nvmem->priv = config->priv; 78716688453SAlexandre Belloni nvmem->type = config->type; 788795ddd18SSrinivas Kandagatla nvmem->reg_read = config->reg_read; 789795ddd18SSrinivas Kandagatla nvmem->reg_write = config->reg_write; 790fd3bb8f5SEvan Green nvmem->keepout = config->keepout; 791fd3bb8f5SEvan Green nvmem->nkeepout = config->nkeepout; 792*1333a677SMichael Walle if (config->of_node) 793*1333a677SMichael Walle nvmem->dev.of_node = config->of_node; 794*1333a677SMichael Walle else if (!config->no_of_node) 795fc2f9970SHeiner Kallweit nvmem->dev.of_node = config->dev->of_node; 796fd0f4906SAndrey Smirnov 797731aa3faSSrinivas Kandagatla switch (config->id) { 798731aa3faSSrinivas Kandagatla case NVMEM_DEVID_NONE: 799fd0f4906SAndrey Smirnov dev_set_name(&nvmem->dev, "%s", config->name); 800731aa3faSSrinivas Kandagatla break; 801731aa3faSSrinivas Kandagatla case NVMEM_DEVID_AUTO: 802731aa3faSSrinivas Kandagatla dev_set_name(&nvmem->dev, "%s%d", config->name, nvmem->id); 803731aa3faSSrinivas Kandagatla break; 804731aa3faSSrinivas Kandagatla default: 805eace75cfSSrinivas Kandagatla dev_set_name(&nvmem->dev, "%s%d", 8065253193dSAban Bedel config->name ? : "nvmem", 8075253193dSAban Bedel config->name ? config->id : nvmem->id); 808731aa3faSSrinivas Kandagatla break; 809fd0f4906SAndrey Smirnov } 810eace75cfSSrinivas Kandagatla 8111716cfe8SAlban Bedel nvmem->read_only = device_property_present(config->dev, "read-only") || 8121716cfe8SAlban Bedel config->read_only || !nvmem->reg_write; 813eace75cfSSrinivas Kandagatla 81484400305SSrinivas Kandagatla #ifdef CONFIG_NVMEM_SYSFS 81584400305SSrinivas Kandagatla nvmem->dev.groups = nvmem_dev_groups; 81684400305SSrinivas Kandagatla #endif 817eace75cfSSrinivas Kandagatla 818fd3bb8f5SEvan Green if (nvmem->nkeepout) { 819fd3bb8f5SEvan Green rval = nvmem_validate_keepouts(nvmem); 820fd3bb8f5SEvan Green if (rval) 821fd3bb8f5SEvan Green goto err_put_device; 822fd3bb8f5SEvan Green } 823fd3bb8f5SEvan Green 824eace75cfSSrinivas Kandagatla dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name); 825eace75cfSSrinivas Kandagatla 826f60442ddSSrinivas Kandagatla rval = device_register(&nvmem->dev); 827b6c217abSAndrew Lunn if (rval) 8283360acdfSJohan Hovold goto err_put_device; 829b6c217abSAndrew Lunn 830b6c217abSAndrew Lunn if (config->compat) { 831ae0c2d72SSrinivas Kandagatla rval = nvmem_sysfs_setup_compat(nvmem, config); 832b6c217abSAndrew Lunn if (rval) 8333360acdfSJohan Hovold goto err_device_del; 834eace75cfSSrinivas Kandagatla } 835eace75cfSSrinivas Kandagatla 836fa72d847SBartosz Golaszewski if (config->cells) { 837fa72d847SBartosz Golaszewski rval = nvmem_add_cells(nvmem, config->cells, config->ncells); 838fa72d847SBartosz Golaszewski if (rval) 839fa72d847SBartosz Golaszewski goto err_teardown_compat; 840fa72d847SBartosz Golaszewski } 841eace75cfSSrinivas Kandagatla 842b985f4cbSBartosz Golaszewski rval = nvmem_add_cells_from_table(nvmem); 843b985f4cbSBartosz Golaszewski if (rval) 844b985f4cbSBartosz Golaszewski goto err_remove_cells; 845b985f4cbSBartosz Golaszewski 846e888d445SBartosz Golaszewski rval = nvmem_add_cells_from_of(nvmem); 847e888d445SBartosz Golaszewski if (rval) 848e888d445SBartosz Golaszewski goto err_remove_cells; 849e888d445SBartosz Golaszewski 850f4853e1cSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_ADD, nvmem); 851bee1138bSBartosz Golaszewski 852eace75cfSSrinivas Kandagatla return nvmem; 8533360acdfSJohan Hovold 854b985f4cbSBartosz Golaszewski err_remove_cells: 855b985f4cbSBartosz Golaszewski nvmem_device_remove_all_cells(nvmem); 856fa72d847SBartosz Golaszewski err_teardown_compat: 857fa72d847SBartosz Golaszewski if (config->compat) 858ae0c2d72SSrinivas Kandagatla nvmem_sysfs_remove_compat(nvmem, config); 8593360acdfSJohan Hovold err_device_del: 8603360acdfSJohan Hovold device_del(&nvmem->dev); 8613360acdfSJohan Hovold err_put_device: 8623360acdfSJohan Hovold put_device(&nvmem->dev); 8633360acdfSJohan Hovold 864b6c217abSAndrew Lunn return ERR_PTR(rval); 865eace75cfSSrinivas Kandagatla } 866eace75cfSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_register); 867eace75cfSSrinivas Kandagatla 868c1de7f43SBartosz Golaszewski static void nvmem_device_release(struct kref *kref) 869c1de7f43SBartosz Golaszewski { 870c1de7f43SBartosz Golaszewski struct nvmem_device *nvmem; 871c1de7f43SBartosz Golaszewski 872c1de7f43SBartosz Golaszewski nvmem = container_of(kref, struct nvmem_device, refcnt); 873c1de7f43SBartosz Golaszewski 874bee1138bSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_REMOVE, nvmem); 875bee1138bSBartosz Golaszewski 876c1de7f43SBartosz Golaszewski if (nvmem->flags & FLAG_COMPAT) 877c1de7f43SBartosz Golaszewski device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); 878c1de7f43SBartosz Golaszewski 879c1de7f43SBartosz Golaszewski nvmem_device_remove_all_cells(nvmem); 880f60442ddSSrinivas Kandagatla device_unregister(&nvmem->dev); 881c1de7f43SBartosz Golaszewski } 882c1de7f43SBartosz Golaszewski 883eace75cfSSrinivas Kandagatla /** 884eace75cfSSrinivas Kandagatla * nvmem_unregister() - Unregister previously registered nvmem device 885eace75cfSSrinivas Kandagatla * 886eace75cfSSrinivas Kandagatla * @nvmem: Pointer to previously registered nvmem device. 887eace75cfSSrinivas Kandagatla */ 888bf58e882SBartosz Golaszewski void nvmem_unregister(struct nvmem_device *nvmem) 889eace75cfSSrinivas Kandagatla { 890c1de7f43SBartosz Golaszewski kref_put(&nvmem->refcnt, nvmem_device_release); 891eace75cfSSrinivas Kandagatla } 892eace75cfSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_unregister); 893eace75cfSSrinivas Kandagatla 894f1f50ecaSAndrey Smirnov static void devm_nvmem_release(struct device *dev, void *res) 895f1f50ecaSAndrey Smirnov { 896bf58e882SBartosz Golaszewski nvmem_unregister(*(struct nvmem_device **)res); 897f1f50ecaSAndrey Smirnov } 898f1f50ecaSAndrey Smirnov 899f1f50ecaSAndrey Smirnov /** 900f1f50ecaSAndrey Smirnov * devm_nvmem_register() - Register a managed nvmem device for given 901f1f50ecaSAndrey Smirnov * nvmem_config. 9023a758071SAndreas Färber * Also creates a binary entry in /sys/bus/nvmem/devices/dev-name/nvmem 903f1f50ecaSAndrey Smirnov * 904b378c779SSrinivas Kandagatla * @dev: Device that uses the nvmem device. 905f1f50ecaSAndrey Smirnov * @config: nvmem device configuration with which nvmem device is created. 906f1f50ecaSAndrey Smirnov * 907f1f50ecaSAndrey Smirnov * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device 908f1f50ecaSAndrey Smirnov * on success. 909f1f50ecaSAndrey Smirnov */ 910f1f50ecaSAndrey Smirnov struct nvmem_device *devm_nvmem_register(struct device *dev, 911f1f50ecaSAndrey Smirnov const struct nvmem_config *config) 912f1f50ecaSAndrey Smirnov { 913f1f50ecaSAndrey Smirnov struct nvmem_device **ptr, *nvmem; 914f1f50ecaSAndrey Smirnov 915f1f50ecaSAndrey Smirnov ptr = devres_alloc(devm_nvmem_release, sizeof(*ptr), GFP_KERNEL); 916f1f50ecaSAndrey Smirnov if (!ptr) 917f1f50ecaSAndrey Smirnov return ERR_PTR(-ENOMEM); 918f1f50ecaSAndrey Smirnov 919f1f50ecaSAndrey Smirnov nvmem = nvmem_register(config); 920f1f50ecaSAndrey Smirnov 921f1f50ecaSAndrey Smirnov if (!IS_ERR(nvmem)) { 922f1f50ecaSAndrey Smirnov *ptr = nvmem; 923f1f50ecaSAndrey Smirnov devres_add(dev, ptr); 924f1f50ecaSAndrey Smirnov } else { 925f1f50ecaSAndrey Smirnov devres_free(ptr); 926f1f50ecaSAndrey Smirnov } 927f1f50ecaSAndrey Smirnov 928f1f50ecaSAndrey Smirnov return nvmem; 929f1f50ecaSAndrey Smirnov } 930f1f50ecaSAndrey Smirnov EXPORT_SYMBOL_GPL(devm_nvmem_register); 931f1f50ecaSAndrey Smirnov 932f1f50ecaSAndrey Smirnov static int devm_nvmem_match(struct device *dev, void *res, void *data) 933f1f50ecaSAndrey Smirnov { 934f1f50ecaSAndrey Smirnov struct nvmem_device **r = res; 935f1f50ecaSAndrey Smirnov 936f1f50ecaSAndrey Smirnov return *r == data; 937f1f50ecaSAndrey Smirnov } 938f1f50ecaSAndrey Smirnov 939f1f50ecaSAndrey Smirnov /** 940f1f50ecaSAndrey Smirnov * devm_nvmem_unregister() - Unregister previously registered managed nvmem 941f1f50ecaSAndrey Smirnov * device. 942f1f50ecaSAndrey Smirnov * 943b378c779SSrinivas Kandagatla * @dev: Device that uses the nvmem device. 944f1f50ecaSAndrey Smirnov * @nvmem: Pointer to previously registered nvmem device. 945f1f50ecaSAndrey Smirnov * 9463a758071SAndreas Färber * Return: Will be negative on error or zero on success. 947f1f50ecaSAndrey Smirnov */ 948f1f50ecaSAndrey Smirnov int devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem) 949f1f50ecaSAndrey Smirnov { 950f1f50ecaSAndrey Smirnov return devres_release(dev, devm_nvmem_release, devm_nvmem_match, nvmem); 951f1f50ecaSAndrey Smirnov } 952f1f50ecaSAndrey Smirnov EXPORT_SYMBOL(devm_nvmem_unregister); 953f1f50ecaSAndrey Smirnov 9548c2a2b8cSThomas Bogendoerfer static struct nvmem_device *__nvmem_device_get(void *data, 9558c2a2b8cSThomas Bogendoerfer int (*match)(struct device *dev, const void *data)) 95669aba794SSrinivas Kandagatla { 95769aba794SSrinivas Kandagatla struct nvmem_device *nvmem = NULL; 9588c2a2b8cSThomas Bogendoerfer struct device *dev; 95969aba794SSrinivas Kandagatla 960c7235ee3SBartosz Golaszewski mutex_lock(&nvmem_mutex); 9618c2a2b8cSThomas Bogendoerfer dev = bus_find_device(&nvmem_bus_type, NULL, data, match); 9628c2a2b8cSThomas Bogendoerfer if (dev) 9638c2a2b8cSThomas Bogendoerfer nvmem = to_nvmem_device(dev); 96469aba794SSrinivas Kandagatla mutex_unlock(&nvmem_mutex); 965c7235ee3SBartosz Golaszewski if (!nvmem) 966c7235ee3SBartosz Golaszewski return ERR_PTR(-EPROBE_DEFER); 96769aba794SSrinivas Kandagatla 96869aba794SSrinivas Kandagatla if (!try_module_get(nvmem->owner)) { 96969aba794SSrinivas Kandagatla dev_err(&nvmem->dev, 97069aba794SSrinivas Kandagatla "could not increase module refcount for cell %s\n", 9715db652c9SBartosz Golaszewski nvmem_dev_name(nvmem)); 97269aba794SSrinivas Kandagatla 97373e9dc4dSAlban Bedel put_device(&nvmem->dev); 97469aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 97569aba794SSrinivas Kandagatla } 97669aba794SSrinivas Kandagatla 977c1de7f43SBartosz Golaszewski kref_get(&nvmem->refcnt); 978c1de7f43SBartosz Golaszewski 97969aba794SSrinivas Kandagatla return nvmem; 98069aba794SSrinivas Kandagatla } 98169aba794SSrinivas Kandagatla 98269aba794SSrinivas Kandagatla static void __nvmem_device_put(struct nvmem_device *nvmem) 98369aba794SSrinivas Kandagatla { 98473e9dc4dSAlban Bedel put_device(&nvmem->dev); 98569aba794SSrinivas Kandagatla module_put(nvmem->owner); 986c1de7f43SBartosz Golaszewski kref_put(&nvmem->refcnt, nvmem_device_release); 98769aba794SSrinivas Kandagatla } 98869aba794SSrinivas Kandagatla 989e701c67cSMasahiro Yamada #if IS_ENABLED(CONFIG_OF) 990e2a5402eSSrinivas Kandagatla /** 991e2a5402eSSrinivas Kandagatla * of_nvmem_device_get() - Get nvmem device from a given id 992e2a5402eSSrinivas Kandagatla * 99329143268SVivek Gautam * @np: Device tree node that uses the nvmem device. 994e2a5402eSSrinivas Kandagatla * @id: nvmem name from nvmem-names property. 995e2a5402eSSrinivas Kandagatla * 996e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device 997e2a5402eSSrinivas Kandagatla * on success. 998e2a5402eSSrinivas Kandagatla */ 999e2a5402eSSrinivas Kandagatla struct nvmem_device *of_nvmem_device_get(struct device_node *np, const char *id) 1000e2a5402eSSrinivas Kandagatla { 1001e2a5402eSSrinivas Kandagatla 1002e2a5402eSSrinivas Kandagatla struct device_node *nvmem_np; 1003b1c194dcSVadym Kochan struct nvmem_device *nvmem; 1004d4e7fef1SAlban Bedel int index = 0; 1005e2a5402eSSrinivas Kandagatla 1006d4e7fef1SAlban Bedel if (id) 1007e2a5402eSSrinivas Kandagatla index = of_property_match_string(np, "nvmem-names", id); 1008e2a5402eSSrinivas Kandagatla 1009e2a5402eSSrinivas Kandagatla nvmem_np = of_parse_phandle(np, "nvmem", index); 1010e2a5402eSSrinivas Kandagatla if (!nvmem_np) 1011d4e7fef1SAlban Bedel return ERR_PTR(-ENOENT); 1012e2a5402eSSrinivas Kandagatla 1013b1c194dcSVadym Kochan nvmem = __nvmem_device_get(nvmem_np, device_match_of_node); 1014b1c194dcSVadym Kochan of_node_put(nvmem_np); 1015b1c194dcSVadym Kochan return nvmem; 1016e2a5402eSSrinivas Kandagatla } 1017e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_nvmem_device_get); 1018e2a5402eSSrinivas Kandagatla #endif 1019e2a5402eSSrinivas Kandagatla 1020e2a5402eSSrinivas Kandagatla /** 1021e2a5402eSSrinivas Kandagatla * nvmem_device_get() - Get nvmem device from a given id 1022e2a5402eSSrinivas Kandagatla * 102329143268SVivek Gautam * @dev: Device that uses the nvmem device. 102429143268SVivek Gautam * @dev_name: name of the requested nvmem device. 1025e2a5402eSSrinivas Kandagatla * 1026e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device 1027e2a5402eSSrinivas Kandagatla * on success. 1028e2a5402eSSrinivas Kandagatla */ 1029e2a5402eSSrinivas Kandagatla struct nvmem_device *nvmem_device_get(struct device *dev, const char *dev_name) 1030e2a5402eSSrinivas Kandagatla { 1031e2a5402eSSrinivas Kandagatla if (dev->of_node) { /* try dt first */ 1032e2a5402eSSrinivas Kandagatla struct nvmem_device *nvmem; 1033e2a5402eSSrinivas Kandagatla 1034e2a5402eSSrinivas Kandagatla nvmem = of_nvmem_device_get(dev->of_node, dev_name); 1035e2a5402eSSrinivas Kandagatla 1036e2a5402eSSrinivas Kandagatla if (!IS_ERR(nvmem) || PTR_ERR(nvmem) == -EPROBE_DEFER) 1037e2a5402eSSrinivas Kandagatla return nvmem; 1038e2a5402eSSrinivas Kandagatla 1039e2a5402eSSrinivas Kandagatla } 1040e2a5402eSSrinivas Kandagatla 10418c2a2b8cSThomas Bogendoerfer return __nvmem_device_get((void *)dev_name, device_match_name); 1042e2a5402eSSrinivas Kandagatla } 1043e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_get); 1044e2a5402eSSrinivas Kandagatla 10458c2a2b8cSThomas Bogendoerfer /** 10468c2a2b8cSThomas Bogendoerfer * nvmem_device_find() - Find nvmem device with matching function 10478c2a2b8cSThomas Bogendoerfer * 10488c2a2b8cSThomas Bogendoerfer * @data: Data to pass to match function 10498c2a2b8cSThomas Bogendoerfer * @match: Callback function to check device 10508c2a2b8cSThomas Bogendoerfer * 10518c2a2b8cSThomas Bogendoerfer * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device 10528c2a2b8cSThomas Bogendoerfer * on success. 10538c2a2b8cSThomas Bogendoerfer */ 10548c2a2b8cSThomas Bogendoerfer struct nvmem_device *nvmem_device_find(void *data, 10558c2a2b8cSThomas Bogendoerfer int (*match)(struct device *dev, const void *data)) 10568c2a2b8cSThomas Bogendoerfer { 10578c2a2b8cSThomas Bogendoerfer return __nvmem_device_get(data, match); 10588c2a2b8cSThomas Bogendoerfer } 10598c2a2b8cSThomas Bogendoerfer EXPORT_SYMBOL_GPL(nvmem_device_find); 10608c2a2b8cSThomas Bogendoerfer 1061e2a5402eSSrinivas Kandagatla static int devm_nvmem_device_match(struct device *dev, void *res, void *data) 1062e2a5402eSSrinivas Kandagatla { 1063e2a5402eSSrinivas Kandagatla struct nvmem_device **nvmem = res; 1064e2a5402eSSrinivas Kandagatla 1065e2a5402eSSrinivas Kandagatla if (WARN_ON(!nvmem || !*nvmem)) 1066e2a5402eSSrinivas Kandagatla return 0; 1067e2a5402eSSrinivas Kandagatla 1068e2a5402eSSrinivas Kandagatla return *nvmem == data; 1069e2a5402eSSrinivas Kandagatla } 1070e2a5402eSSrinivas Kandagatla 1071e2a5402eSSrinivas Kandagatla static void devm_nvmem_device_release(struct device *dev, void *res) 1072e2a5402eSSrinivas Kandagatla { 1073e2a5402eSSrinivas Kandagatla nvmem_device_put(*(struct nvmem_device **)res); 1074e2a5402eSSrinivas Kandagatla } 1075e2a5402eSSrinivas Kandagatla 1076e2a5402eSSrinivas Kandagatla /** 1077e2a5402eSSrinivas Kandagatla * devm_nvmem_device_put() - put alredy got nvmem device 1078e2a5402eSSrinivas Kandagatla * 107929143268SVivek Gautam * @dev: Device that uses the nvmem device. 1080e2a5402eSSrinivas Kandagatla * @nvmem: pointer to nvmem device allocated by devm_nvmem_cell_get(), 1081e2a5402eSSrinivas Kandagatla * that needs to be released. 1082e2a5402eSSrinivas Kandagatla */ 1083e2a5402eSSrinivas Kandagatla void devm_nvmem_device_put(struct device *dev, struct nvmem_device *nvmem) 1084e2a5402eSSrinivas Kandagatla { 1085e2a5402eSSrinivas Kandagatla int ret; 1086e2a5402eSSrinivas Kandagatla 1087e2a5402eSSrinivas Kandagatla ret = devres_release(dev, devm_nvmem_device_release, 1088e2a5402eSSrinivas Kandagatla devm_nvmem_device_match, nvmem); 1089e2a5402eSSrinivas Kandagatla 1090e2a5402eSSrinivas Kandagatla WARN_ON(ret); 1091e2a5402eSSrinivas Kandagatla } 1092e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_device_put); 1093e2a5402eSSrinivas Kandagatla 1094e2a5402eSSrinivas Kandagatla /** 1095e2a5402eSSrinivas Kandagatla * nvmem_device_put() - put alredy got nvmem device 1096e2a5402eSSrinivas Kandagatla * 1097e2a5402eSSrinivas Kandagatla * @nvmem: pointer to nvmem device that needs to be released. 1098e2a5402eSSrinivas Kandagatla */ 1099e2a5402eSSrinivas Kandagatla void nvmem_device_put(struct nvmem_device *nvmem) 1100e2a5402eSSrinivas Kandagatla { 1101e2a5402eSSrinivas Kandagatla __nvmem_device_put(nvmem); 1102e2a5402eSSrinivas Kandagatla } 1103e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_put); 1104e2a5402eSSrinivas Kandagatla 1105e2a5402eSSrinivas Kandagatla /** 1106e2a5402eSSrinivas Kandagatla * devm_nvmem_device_get() - Get nvmem cell of device form a given id 1107e2a5402eSSrinivas Kandagatla * 110829143268SVivek Gautam * @dev: Device that requests the nvmem device. 110929143268SVivek Gautam * @id: name id for the requested nvmem device. 1110e2a5402eSSrinivas Kandagatla * 1111e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_cell 1112e2a5402eSSrinivas Kandagatla * on success. The nvmem_cell will be freed by the automatically once the 1113e2a5402eSSrinivas Kandagatla * device is freed. 1114e2a5402eSSrinivas Kandagatla */ 1115e2a5402eSSrinivas Kandagatla struct nvmem_device *devm_nvmem_device_get(struct device *dev, const char *id) 1116e2a5402eSSrinivas Kandagatla { 1117e2a5402eSSrinivas Kandagatla struct nvmem_device **ptr, *nvmem; 1118e2a5402eSSrinivas Kandagatla 1119e2a5402eSSrinivas Kandagatla ptr = devres_alloc(devm_nvmem_device_release, sizeof(*ptr), GFP_KERNEL); 1120e2a5402eSSrinivas Kandagatla if (!ptr) 1121e2a5402eSSrinivas Kandagatla return ERR_PTR(-ENOMEM); 1122e2a5402eSSrinivas Kandagatla 1123e2a5402eSSrinivas Kandagatla nvmem = nvmem_device_get(dev, id); 1124e2a5402eSSrinivas Kandagatla if (!IS_ERR(nvmem)) { 1125e2a5402eSSrinivas Kandagatla *ptr = nvmem; 1126e2a5402eSSrinivas Kandagatla devres_add(dev, ptr); 1127e2a5402eSSrinivas Kandagatla } else { 1128e2a5402eSSrinivas Kandagatla devres_free(ptr); 1129e2a5402eSSrinivas Kandagatla } 1130e2a5402eSSrinivas Kandagatla 1131e2a5402eSSrinivas Kandagatla return nvmem; 1132e2a5402eSSrinivas Kandagatla } 1133e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_device_get); 1134e2a5402eSSrinivas Kandagatla 1135506157beSBartosz Golaszewski static struct nvmem_cell * 1136506157beSBartosz Golaszewski nvmem_cell_get_from_lookup(struct device *dev, const char *con_id) 113769aba794SSrinivas Kandagatla { 1138506157beSBartosz Golaszewski struct nvmem_cell *cell = ERR_PTR(-ENOENT); 1139506157beSBartosz Golaszewski struct nvmem_cell_lookup *lookup; 114069aba794SSrinivas Kandagatla struct nvmem_device *nvmem; 1141506157beSBartosz Golaszewski const char *dev_id; 114269aba794SSrinivas Kandagatla 1143506157beSBartosz Golaszewski if (!dev) 1144506157beSBartosz Golaszewski return ERR_PTR(-EINVAL); 114569aba794SSrinivas Kandagatla 1146506157beSBartosz Golaszewski dev_id = dev_name(dev); 1147506157beSBartosz Golaszewski 1148506157beSBartosz Golaszewski mutex_lock(&nvmem_lookup_mutex); 1149506157beSBartosz Golaszewski 1150506157beSBartosz Golaszewski list_for_each_entry(lookup, &nvmem_lookup_list, node) { 1151506157beSBartosz Golaszewski if ((strcmp(lookup->dev_id, dev_id) == 0) && 1152506157beSBartosz Golaszewski (strcmp(lookup->con_id, con_id) == 0)) { 1153506157beSBartosz Golaszewski /* This is the right entry. */ 11548c2a2b8cSThomas Bogendoerfer nvmem = __nvmem_device_get((void *)lookup->nvmem_name, 11558c2a2b8cSThomas Bogendoerfer device_match_name); 1156cccb3b19SBartosz Golaszewski if (IS_ERR(nvmem)) { 1157506157beSBartosz Golaszewski /* Provider may not be registered yet. */ 1158cccb3b19SBartosz Golaszewski cell = ERR_CAST(nvmem); 11599bfd8198SAlban Bedel break; 1160506157beSBartosz Golaszewski } 1161506157beSBartosz Golaszewski 1162506157beSBartosz Golaszewski cell = nvmem_find_cell_by_name(nvmem, 1163506157beSBartosz Golaszewski lookup->cell_name); 1164506157beSBartosz Golaszewski if (!cell) { 1165506157beSBartosz Golaszewski __nvmem_device_put(nvmem); 1166cccb3b19SBartosz Golaszewski cell = ERR_PTR(-ENOENT); 1167506157beSBartosz Golaszewski } 11689bfd8198SAlban Bedel break; 1169506157beSBartosz Golaszewski } 1170506157beSBartosz Golaszewski } 1171506157beSBartosz Golaszewski 1172506157beSBartosz Golaszewski mutex_unlock(&nvmem_lookup_mutex); 117369aba794SSrinivas Kandagatla return cell; 117469aba794SSrinivas Kandagatla } 117569aba794SSrinivas Kandagatla 1176e701c67cSMasahiro Yamada #if IS_ENABLED(CONFIG_OF) 11773c53e235SArnd Bergmann static struct nvmem_cell * 11780749aa25SSrinivas Kandagatla nvmem_find_cell_by_node(struct nvmem_device *nvmem, struct device_node *np) 11793c53e235SArnd Bergmann { 11801c832674SAlban Bedel struct nvmem_cell *iter, *cell = NULL; 11813c53e235SArnd Bergmann 11823c53e235SArnd Bergmann mutex_lock(&nvmem_mutex); 11831c832674SAlban Bedel list_for_each_entry(iter, &nvmem->cells, node) { 11841c832674SAlban Bedel if (np == iter->np) { 11851c832674SAlban Bedel cell = iter; 11863c53e235SArnd Bergmann break; 11873c53e235SArnd Bergmann } 11881c832674SAlban Bedel } 11893c53e235SArnd Bergmann mutex_unlock(&nvmem_mutex); 11903c53e235SArnd Bergmann 11913c53e235SArnd Bergmann return cell; 11923c53e235SArnd Bergmann } 11933c53e235SArnd Bergmann 119469aba794SSrinivas Kandagatla /** 119569aba794SSrinivas Kandagatla * of_nvmem_cell_get() - Get a nvmem cell from given device node and cell id 119669aba794SSrinivas Kandagatla * 119729143268SVivek Gautam * @np: Device tree node that uses the nvmem cell. 1198165589f0SBartosz Golaszewski * @id: nvmem cell name from nvmem-cell-names property, or NULL 1199fd0c478cSVivek Gautam * for the cell at index 0 (the lone cell with no accompanying 1200fd0c478cSVivek Gautam * nvmem-cell-names property). 120169aba794SSrinivas Kandagatla * 120269aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 120369aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 120469aba794SSrinivas Kandagatla * nvmem_cell_put(). 120569aba794SSrinivas Kandagatla */ 1206165589f0SBartosz Golaszewski struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *id) 120769aba794SSrinivas Kandagatla { 120869aba794SSrinivas Kandagatla struct device_node *cell_np, *nvmem_np; 120969aba794SSrinivas Kandagatla struct nvmem_device *nvmem; 1210e888d445SBartosz Golaszewski struct nvmem_cell *cell; 1211fd0c478cSVivek Gautam int index = 0; 121269aba794SSrinivas Kandagatla 1213fd0c478cSVivek Gautam /* if cell name exists, find index to the name */ 1214165589f0SBartosz Golaszewski if (id) 1215165589f0SBartosz Golaszewski index = of_property_match_string(np, "nvmem-cell-names", id); 121669aba794SSrinivas Kandagatla 121769aba794SSrinivas Kandagatla cell_np = of_parse_phandle(np, "nvmem-cells", index); 121869aba794SSrinivas Kandagatla if (!cell_np) 12195087cc19SAlban Bedel return ERR_PTR(-ENOENT); 122069aba794SSrinivas Kandagatla 122169aba794SSrinivas Kandagatla nvmem_np = of_get_next_parent(cell_np); 122269aba794SSrinivas Kandagatla if (!nvmem_np) 122369aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 122469aba794SSrinivas Kandagatla 12258c2a2b8cSThomas Bogendoerfer nvmem = __nvmem_device_get(nvmem_np, device_match_of_node); 1226aad8d097SMasahiro Yamada of_node_put(nvmem_np); 122769aba794SSrinivas Kandagatla if (IS_ERR(nvmem)) 122869aba794SSrinivas Kandagatla return ERR_CAST(nvmem); 122969aba794SSrinivas Kandagatla 12300749aa25SSrinivas Kandagatla cell = nvmem_find_cell_by_node(nvmem, cell_np); 123169aba794SSrinivas Kandagatla if (!cell) { 1232e888d445SBartosz Golaszewski __nvmem_device_put(nvmem); 1233e888d445SBartosz Golaszewski return ERR_PTR(-ENOENT); 123469aba794SSrinivas Kandagatla } 123569aba794SSrinivas Kandagatla 123669aba794SSrinivas Kandagatla return cell; 123769aba794SSrinivas Kandagatla } 123869aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_nvmem_cell_get); 123969aba794SSrinivas Kandagatla #endif 124069aba794SSrinivas Kandagatla 124169aba794SSrinivas Kandagatla /** 124269aba794SSrinivas Kandagatla * nvmem_cell_get() - Get nvmem cell of device form a given cell name 124369aba794SSrinivas Kandagatla * 124429143268SVivek Gautam * @dev: Device that requests the nvmem cell. 1245165589f0SBartosz Golaszewski * @id: nvmem cell name to get (this corresponds with the name from the 1246165589f0SBartosz Golaszewski * nvmem-cell-names property for DT systems and with the con_id from 1247165589f0SBartosz Golaszewski * the lookup entry for non-DT systems). 124869aba794SSrinivas Kandagatla * 124969aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 125069aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 125169aba794SSrinivas Kandagatla * nvmem_cell_put(). 125269aba794SSrinivas Kandagatla */ 1253165589f0SBartosz Golaszewski struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *id) 125469aba794SSrinivas Kandagatla { 125569aba794SSrinivas Kandagatla struct nvmem_cell *cell; 125669aba794SSrinivas Kandagatla 125769aba794SSrinivas Kandagatla if (dev->of_node) { /* try dt first */ 1258165589f0SBartosz Golaszewski cell = of_nvmem_cell_get(dev->of_node, id); 125969aba794SSrinivas Kandagatla if (!IS_ERR(cell) || PTR_ERR(cell) == -EPROBE_DEFER) 126069aba794SSrinivas Kandagatla return cell; 126169aba794SSrinivas Kandagatla } 126269aba794SSrinivas Kandagatla 1263165589f0SBartosz Golaszewski /* NULL cell id only allowed for device tree; invalid otherwise */ 1264165589f0SBartosz Golaszewski if (!id) 126587ed1405SDouglas Anderson return ERR_PTR(-EINVAL); 126687ed1405SDouglas Anderson 1267165589f0SBartosz Golaszewski return nvmem_cell_get_from_lookup(dev, id); 126869aba794SSrinivas Kandagatla } 126969aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_get); 127069aba794SSrinivas Kandagatla 127169aba794SSrinivas Kandagatla static void devm_nvmem_cell_release(struct device *dev, void *res) 127269aba794SSrinivas Kandagatla { 127369aba794SSrinivas Kandagatla nvmem_cell_put(*(struct nvmem_cell **)res); 127469aba794SSrinivas Kandagatla } 127569aba794SSrinivas Kandagatla 127669aba794SSrinivas Kandagatla /** 127769aba794SSrinivas Kandagatla * devm_nvmem_cell_get() - Get nvmem cell of device form a given id 127869aba794SSrinivas Kandagatla * 127929143268SVivek Gautam * @dev: Device that requests the nvmem cell. 128029143268SVivek Gautam * @id: nvmem cell name id to get. 128169aba794SSrinivas Kandagatla * 128269aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 128369aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 128469aba794SSrinivas Kandagatla * automatically once the device is freed. 128569aba794SSrinivas Kandagatla */ 128669aba794SSrinivas Kandagatla struct nvmem_cell *devm_nvmem_cell_get(struct device *dev, const char *id) 128769aba794SSrinivas Kandagatla { 128869aba794SSrinivas Kandagatla struct nvmem_cell **ptr, *cell; 128969aba794SSrinivas Kandagatla 129069aba794SSrinivas Kandagatla ptr = devres_alloc(devm_nvmem_cell_release, sizeof(*ptr), GFP_KERNEL); 129169aba794SSrinivas Kandagatla if (!ptr) 129269aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 129369aba794SSrinivas Kandagatla 129469aba794SSrinivas Kandagatla cell = nvmem_cell_get(dev, id); 129569aba794SSrinivas Kandagatla if (!IS_ERR(cell)) { 129669aba794SSrinivas Kandagatla *ptr = cell; 129769aba794SSrinivas Kandagatla devres_add(dev, ptr); 129869aba794SSrinivas Kandagatla } else { 129969aba794SSrinivas Kandagatla devres_free(ptr); 130069aba794SSrinivas Kandagatla } 130169aba794SSrinivas Kandagatla 130269aba794SSrinivas Kandagatla return cell; 130369aba794SSrinivas Kandagatla } 130469aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_cell_get); 130569aba794SSrinivas Kandagatla 130669aba794SSrinivas Kandagatla static int devm_nvmem_cell_match(struct device *dev, void *res, void *data) 130769aba794SSrinivas Kandagatla { 130869aba794SSrinivas Kandagatla struct nvmem_cell **c = res; 130969aba794SSrinivas Kandagatla 131069aba794SSrinivas Kandagatla if (WARN_ON(!c || !*c)) 131169aba794SSrinivas Kandagatla return 0; 131269aba794SSrinivas Kandagatla 131369aba794SSrinivas Kandagatla return *c == data; 131469aba794SSrinivas Kandagatla } 131569aba794SSrinivas Kandagatla 131669aba794SSrinivas Kandagatla /** 131769aba794SSrinivas Kandagatla * devm_nvmem_cell_put() - Release previously allocated nvmem cell 131869aba794SSrinivas Kandagatla * from devm_nvmem_cell_get. 131969aba794SSrinivas Kandagatla * 132029143268SVivek Gautam * @dev: Device that requests the nvmem cell. 132129143268SVivek Gautam * @cell: Previously allocated nvmem cell by devm_nvmem_cell_get(). 132269aba794SSrinivas Kandagatla */ 132369aba794SSrinivas Kandagatla void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell) 132469aba794SSrinivas Kandagatla { 132569aba794SSrinivas Kandagatla int ret; 132669aba794SSrinivas Kandagatla 132769aba794SSrinivas Kandagatla ret = devres_release(dev, devm_nvmem_cell_release, 132869aba794SSrinivas Kandagatla devm_nvmem_cell_match, cell); 132969aba794SSrinivas Kandagatla 133069aba794SSrinivas Kandagatla WARN_ON(ret); 133169aba794SSrinivas Kandagatla } 133269aba794SSrinivas Kandagatla EXPORT_SYMBOL(devm_nvmem_cell_put); 133369aba794SSrinivas Kandagatla 133469aba794SSrinivas Kandagatla /** 133569aba794SSrinivas Kandagatla * nvmem_cell_put() - Release previously allocated nvmem cell. 133669aba794SSrinivas Kandagatla * 133729143268SVivek Gautam * @cell: Previously allocated nvmem cell by nvmem_cell_get(). 133869aba794SSrinivas Kandagatla */ 133969aba794SSrinivas Kandagatla void nvmem_cell_put(struct nvmem_cell *cell) 134069aba794SSrinivas Kandagatla { 134169aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 134269aba794SSrinivas Kandagatla 134369aba794SSrinivas Kandagatla __nvmem_device_put(nvmem); 134469aba794SSrinivas Kandagatla } 134569aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_put); 134669aba794SSrinivas Kandagatla 1347f7c04f16SMasahiro Yamada static void nvmem_shift_read_buffer_in_place(struct nvmem_cell *cell, void *buf) 134869aba794SSrinivas Kandagatla { 134969aba794SSrinivas Kandagatla u8 *p, *b; 13502fe518feSJorge Ramirez-Ortiz int i, extra, bit_offset = cell->bit_offset; 135169aba794SSrinivas Kandagatla 135269aba794SSrinivas Kandagatla p = b = buf; 135369aba794SSrinivas Kandagatla if (bit_offset) { 135469aba794SSrinivas Kandagatla /* First shift */ 135569aba794SSrinivas Kandagatla *b++ >>= bit_offset; 135669aba794SSrinivas Kandagatla 135769aba794SSrinivas Kandagatla /* setup rest of the bytes if any */ 135869aba794SSrinivas Kandagatla for (i = 1; i < cell->bytes; i++) { 135969aba794SSrinivas Kandagatla /* Get bits from next byte and shift them towards msb */ 136069aba794SSrinivas Kandagatla *p |= *b << (BITS_PER_BYTE - bit_offset); 136169aba794SSrinivas Kandagatla 136269aba794SSrinivas Kandagatla p = b; 136369aba794SSrinivas Kandagatla *b++ >>= bit_offset; 136469aba794SSrinivas Kandagatla } 13652fe518feSJorge Ramirez-Ortiz } else { 13662fe518feSJorge Ramirez-Ortiz /* point to the msb */ 13672fe518feSJorge Ramirez-Ortiz p += cell->bytes - 1; 13682fe518feSJorge Ramirez-Ortiz } 136969aba794SSrinivas Kandagatla 137069aba794SSrinivas Kandagatla /* result fits in less bytes */ 13712fe518feSJorge Ramirez-Ortiz extra = cell->bytes - DIV_ROUND_UP(cell->nbits, BITS_PER_BYTE); 13722fe518feSJorge Ramirez-Ortiz while (--extra >= 0) 137369aba794SSrinivas Kandagatla *p-- = 0; 13742fe518feSJorge Ramirez-Ortiz 137569aba794SSrinivas Kandagatla /* clear msb bits if any leftover in the last byte */ 137669aba794SSrinivas Kandagatla *p &= GENMASK((cell->nbits%BITS_PER_BYTE) - 1, 0); 137769aba794SSrinivas Kandagatla } 137869aba794SSrinivas Kandagatla 137969aba794SSrinivas Kandagatla static int __nvmem_cell_read(struct nvmem_device *nvmem, 138069aba794SSrinivas Kandagatla struct nvmem_cell *cell, 138169aba794SSrinivas Kandagatla void *buf, size_t *len) 138269aba794SSrinivas Kandagatla { 138369aba794SSrinivas Kandagatla int rc; 138469aba794SSrinivas Kandagatla 1385795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, cell->offset, buf, cell->bytes); 138669aba794SSrinivas Kandagatla 1387287980e4SArnd Bergmann if (rc) 138869aba794SSrinivas Kandagatla return rc; 138969aba794SSrinivas Kandagatla 139069aba794SSrinivas Kandagatla /* shift bits in-place */ 1391cbf854abSAxel Lin if (cell->bit_offset || cell->nbits) 139269aba794SSrinivas Kandagatla nvmem_shift_read_buffer_in_place(cell, buf); 139369aba794SSrinivas Kandagatla 13943b4a6877SVivek Gautam if (len) 139569aba794SSrinivas Kandagatla *len = cell->bytes; 139669aba794SSrinivas Kandagatla 139769aba794SSrinivas Kandagatla return 0; 139869aba794SSrinivas Kandagatla } 139969aba794SSrinivas Kandagatla 140069aba794SSrinivas Kandagatla /** 140169aba794SSrinivas Kandagatla * nvmem_cell_read() - Read a given nvmem cell 140269aba794SSrinivas Kandagatla * 140369aba794SSrinivas Kandagatla * @cell: nvmem cell to be read. 14043b4a6877SVivek Gautam * @len: pointer to length of cell which will be populated on successful read; 14053b4a6877SVivek Gautam * can be NULL. 140669aba794SSrinivas Kandagatla * 1407b577fafcSBrian Norris * Return: ERR_PTR() on error or a valid pointer to a buffer on success. The 1408b577fafcSBrian Norris * buffer should be freed by the consumer with a kfree(). 140969aba794SSrinivas Kandagatla */ 141069aba794SSrinivas Kandagatla void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len) 141169aba794SSrinivas Kandagatla { 141269aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 141369aba794SSrinivas Kandagatla u8 *buf; 141469aba794SSrinivas Kandagatla int rc; 141569aba794SSrinivas Kandagatla 1416795ddd18SSrinivas Kandagatla if (!nvmem) 141769aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 141869aba794SSrinivas Kandagatla 141969aba794SSrinivas Kandagatla buf = kzalloc(cell->bytes, GFP_KERNEL); 142069aba794SSrinivas Kandagatla if (!buf) 142169aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 142269aba794SSrinivas Kandagatla 142369aba794SSrinivas Kandagatla rc = __nvmem_cell_read(nvmem, cell, buf, len); 1424287980e4SArnd Bergmann if (rc) { 142569aba794SSrinivas Kandagatla kfree(buf); 142669aba794SSrinivas Kandagatla return ERR_PTR(rc); 142769aba794SSrinivas Kandagatla } 142869aba794SSrinivas Kandagatla 142969aba794SSrinivas Kandagatla return buf; 143069aba794SSrinivas Kandagatla } 143169aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_read); 143269aba794SSrinivas Kandagatla 1433f7c04f16SMasahiro Yamada static void *nvmem_cell_prepare_write_buffer(struct nvmem_cell *cell, 143469aba794SSrinivas Kandagatla u8 *_buf, int len) 143569aba794SSrinivas Kandagatla { 143669aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 143769aba794SSrinivas Kandagatla int i, rc, nbits, bit_offset = cell->bit_offset; 143869aba794SSrinivas Kandagatla u8 v, *p, *buf, *b, pbyte, pbits; 143969aba794SSrinivas Kandagatla 144069aba794SSrinivas Kandagatla nbits = cell->nbits; 144169aba794SSrinivas Kandagatla buf = kzalloc(cell->bytes, GFP_KERNEL); 144269aba794SSrinivas Kandagatla if (!buf) 144369aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 144469aba794SSrinivas Kandagatla 144569aba794SSrinivas Kandagatla memcpy(buf, _buf, len); 144669aba794SSrinivas Kandagatla p = b = buf; 144769aba794SSrinivas Kandagatla 144869aba794SSrinivas Kandagatla if (bit_offset) { 144969aba794SSrinivas Kandagatla pbyte = *b; 145069aba794SSrinivas Kandagatla *b <<= bit_offset; 145169aba794SSrinivas Kandagatla 145269aba794SSrinivas Kandagatla /* setup the first byte with lsb bits from nvmem */ 1453795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, cell->offset, &v, 1); 145450808bfcSMathieu Malaterre if (rc) 145550808bfcSMathieu Malaterre goto err; 145669aba794SSrinivas Kandagatla *b++ |= GENMASK(bit_offset - 1, 0) & v; 145769aba794SSrinivas Kandagatla 145869aba794SSrinivas Kandagatla /* setup rest of the byte if any */ 145969aba794SSrinivas Kandagatla for (i = 1; i < cell->bytes; i++) { 146069aba794SSrinivas Kandagatla /* Get last byte bits and shift them towards lsb */ 146169aba794SSrinivas Kandagatla pbits = pbyte >> (BITS_PER_BYTE - 1 - bit_offset); 146269aba794SSrinivas Kandagatla pbyte = *b; 146369aba794SSrinivas Kandagatla p = b; 146469aba794SSrinivas Kandagatla *b <<= bit_offset; 146569aba794SSrinivas Kandagatla *b++ |= pbits; 146669aba794SSrinivas Kandagatla } 146769aba794SSrinivas Kandagatla } 146869aba794SSrinivas Kandagatla 146969aba794SSrinivas Kandagatla /* if it's not end on byte boundary */ 147069aba794SSrinivas Kandagatla if ((nbits + bit_offset) % BITS_PER_BYTE) { 147169aba794SSrinivas Kandagatla /* setup the last byte with msb bits from nvmem */ 1472795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, 147369aba794SSrinivas Kandagatla cell->offset + cell->bytes - 1, &v, 1); 147450808bfcSMathieu Malaterre if (rc) 147550808bfcSMathieu Malaterre goto err; 147669aba794SSrinivas Kandagatla *p |= GENMASK(7, (nbits + bit_offset) % BITS_PER_BYTE) & v; 147769aba794SSrinivas Kandagatla 147869aba794SSrinivas Kandagatla } 147969aba794SSrinivas Kandagatla 148069aba794SSrinivas Kandagatla return buf; 148150808bfcSMathieu Malaterre err: 148250808bfcSMathieu Malaterre kfree(buf); 148350808bfcSMathieu Malaterre return ERR_PTR(rc); 148469aba794SSrinivas Kandagatla } 148569aba794SSrinivas Kandagatla 148669aba794SSrinivas Kandagatla /** 148769aba794SSrinivas Kandagatla * nvmem_cell_write() - Write to a given nvmem cell 148869aba794SSrinivas Kandagatla * 148969aba794SSrinivas Kandagatla * @cell: nvmem cell to be written. 149069aba794SSrinivas Kandagatla * @buf: Buffer to be written. 149169aba794SSrinivas Kandagatla * @len: length of buffer to be written to nvmem cell. 149269aba794SSrinivas Kandagatla * 149369aba794SSrinivas Kandagatla * Return: length of bytes written or negative on failure. 149469aba794SSrinivas Kandagatla */ 149569aba794SSrinivas Kandagatla int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len) 149669aba794SSrinivas Kandagatla { 149769aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 149869aba794SSrinivas Kandagatla int rc; 149969aba794SSrinivas Kandagatla 1500795ddd18SSrinivas Kandagatla if (!nvmem || nvmem->read_only || 150169aba794SSrinivas Kandagatla (cell->bit_offset == 0 && len != cell->bytes)) 150269aba794SSrinivas Kandagatla return -EINVAL; 150369aba794SSrinivas Kandagatla 150469aba794SSrinivas Kandagatla if (cell->bit_offset || cell->nbits) { 150569aba794SSrinivas Kandagatla buf = nvmem_cell_prepare_write_buffer(cell, buf, len); 150669aba794SSrinivas Kandagatla if (IS_ERR(buf)) 150769aba794SSrinivas Kandagatla return PTR_ERR(buf); 150869aba794SSrinivas Kandagatla } 150969aba794SSrinivas Kandagatla 1510795ddd18SSrinivas Kandagatla rc = nvmem_reg_write(nvmem, cell->offset, buf, cell->bytes); 151169aba794SSrinivas Kandagatla 151269aba794SSrinivas Kandagatla /* free the tmp buffer */ 1513ace22170SAxel Lin if (cell->bit_offset || cell->nbits) 151469aba794SSrinivas Kandagatla kfree(buf); 151569aba794SSrinivas Kandagatla 1516287980e4SArnd Bergmann if (rc) 151769aba794SSrinivas Kandagatla return rc; 151869aba794SSrinivas Kandagatla 151969aba794SSrinivas Kandagatla return len; 152069aba794SSrinivas Kandagatla } 152169aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_write); 152269aba794SSrinivas Kandagatla 15236bb317ceSYangtao Li static int nvmem_cell_read_common(struct device *dev, const char *cell_id, 15246bb317ceSYangtao Li void *val, size_t count) 15250a9b2d1cSFabrice Gasnier { 15260a9b2d1cSFabrice Gasnier struct nvmem_cell *cell; 15270a9b2d1cSFabrice Gasnier void *buf; 15280a9b2d1cSFabrice Gasnier size_t len; 15290a9b2d1cSFabrice Gasnier 15300a9b2d1cSFabrice Gasnier cell = nvmem_cell_get(dev, cell_id); 15310a9b2d1cSFabrice Gasnier if (IS_ERR(cell)) 15320a9b2d1cSFabrice Gasnier return PTR_ERR(cell); 15330a9b2d1cSFabrice Gasnier 15340a9b2d1cSFabrice Gasnier buf = nvmem_cell_read(cell, &len); 15350a9b2d1cSFabrice Gasnier if (IS_ERR(buf)) { 15360a9b2d1cSFabrice Gasnier nvmem_cell_put(cell); 15370a9b2d1cSFabrice Gasnier return PTR_ERR(buf); 15380a9b2d1cSFabrice Gasnier } 15396bb317ceSYangtao Li if (len != count) { 15400a9b2d1cSFabrice Gasnier kfree(buf); 15410a9b2d1cSFabrice Gasnier nvmem_cell_put(cell); 15420a9b2d1cSFabrice Gasnier return -EINVAL; 15430a9b2d1cSFabrice Gasnier } 15446bb317ceSYangtao Li memcpy(val, buf, count); 15450a9b2d1cSFabrice Gasnier kfree(buf); 15460a9b2d1cSFabrice Gasnier nvmem_cell_put(cell); 15470a9b2d1cSFabrice Gasnier 15480a9b2d1cSFabrice Gasnier return 0; 15490a9b2d1cSFabrice Gasnier } 15506bb317ceSYangtao Li 15516bb317ceSYangtao Li /** 15525037d368SAndreas Färber * nvmem_cell_read_u8() - Read a cell value as a u8 15535037d368SAndreas Färber * 15545037d368SAndreas Färber * @dev: Device that requests the nvmem cell. 15555037d368SAndreas Färber * @cell_id: Name of nvmem cell to read. 15565037d368SAndreas Färber * @val: pointer to output value. 15575037d368SAndreas Färber * 15585037d368SAndreas Färber * Return: 0 on success or negative errno. 15595037d368SAndreas Färber */ 15605037d368SAndreas Färber int nvmem_cell_read_u8(struct device *dev, const char *cell_id, u8 *val) 15615037d368SAndreas Färber { 15625037d368SAndreas Färber return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val)); 15635037d368SAndreas Färber } 15645037d368SAndreas Färber EXPORT_SYMBOL_GPL(nvmem_cell_read_u8); 15655037d368SAndreas Färber 15665037d368SAndreas Färber /** 15673a758071SAndreas Färber * nvmem_cell_read_u16() - Read a cell value as a u16 15686bb317ceSYangtao Li * 15696bb317ceSYangtao Li * @dev: Device that requests the nvmem cell. 15706bb317ceSYangtao Li * @cell_id: Name of nvmem cell to read. 15716bb317ceSYangtao Li * @val: pointer to output value. 15726bb317ceSYangtao Li * 15736bb317ceSYangtao Li * Return: 0 on success or negative errno. 15746bb317ceSYangtao Li */ 15756bb317ceSYangtao Li int nvmem_cell_read_u16(struct device *dev, const char *cell_id, u16 *val) 15766bb317ceSYangtao Li { 15776bb317ceSYangtao Li return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val)); 15786bb317ceSYangtao Li } 15790a9b2d1cSFabrice Gasnier EXPORT_SYMBOL_GPL(nvmem_cell_read_u16); 15800a9b2d1cSFabrice Gasnier 15810a9b2d1cSFabrice Gasnier /** 15823a758071SAndreas Färber * nvmem_cell_read_u32() - Read a cell value as a u32 1583d026d70aSLeonard Crestez * 1584d026d70aSLeonard Crestez * @dev: Device that requests the nvmem cell. 1585d026d70aSLeonard Crestez * @cell_id: Name of nvmem cell to read. 1586d026d70aSLeonard Crestez * @val: pointer to output value. 1587d026d70aSLeonard Crestez * 1588d026d70aSLeonard Crestez * Return: 0 on success or negative errno. 1589d026d70aSLeonard Crestez */ 1590d026d70aSLeonard Crestez int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val) 1591d026d70aSLeonard Crestez { 15926bb317ceSYangtao Li return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val)); 1593d026d70aSLeonard Crestez } 1594d026d70aSLeonard Crestez EXPORT_SYMBOL_GPL(nvmem_cell_read_u32); 1595d026d70aSLeonard Crestez 1596d026d70aSLeonard Crestez /** 15973a758071SAndreas Färber * nvmem_cell_read_u64() - Read a cell value as a u64 15988b977c54SYangtao Li * 15998b977c54SYangtao Li * @dev: Device that requests the nvmem cell. 16008b977c54SYangtao Li * @cell_id: Name of nvmem cell to read. 16018b977c54SYangtao Li * @val: pointer to output value. 16028b977c54SYangtao Li * 16038b977c54SYangtao Li * Return: 0 on success or negative errno. 16048b977c54SYangtao Li */ 16058b977c54SYangtao Li int nvmem_cell_read_u64(struct device *dev, const char *cell_id, u64 *val) 16068b977c54SYangtao Li { 16078b977c54SYangtao Li return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val)); 16088b977c54SYangtao Li } 16098b977c54SYangtao Li EXPORT_SYMBOL_GPL(nvmem_cell_read_u64); 16108b977c54SYangtao Li 1611a28e824fSDouglas Anderson static void *nvmem_cell_read_variable_common(struct device *dev, 1612a28e824fSDouglas Anderson const char *cell_id, 1613a28e824fSDouglas Anderson size_t max_len, size_t *len) 1614a28e824fSDouglas Anderson { 1615a28e824fSDouglas Anderson struct nvmem_cell *cell; 1616a28e824fSDouglas Anderson int nbits; 1617a28e824fSDouglas Anderson void *buf; 1618a28e824fSDouglas Anderson 1619a28e824fSDouglas Anderson cell = nvmem_cell_get(dev, cell_id); 1620a28e824fSDouglas Anderson if (IS_ERR(cell)) 1621a28e824fSDouglas Anderson return cell; 1622a28e824fSDouglas Anderson 1623a28e824fSDouglas Anderson nbits = cell->nbits; 1624a28e824fSDouglas Anderson buf = nvmem_cell_read(cell, len); 1625a28e824fSDouglas Anderson nvmem_cell_put(cell); 1626a28e824fSDouglas Anderson if (IS_ERR(buf)) 1627a28e824fSDouglas Anderson return buf; 1628a28e824fSDouglas Anderson 1629a28e824fSDouglas Anderson /* 1630a28e824fSDouglas Anderson * If nbits is set then nvmem_cell_read() can significantly exaggerate 1631a28e824fSDouglas Anderson * the length of the real data. Throw away the extra junk. 1632a28e824fSDouglas Anderson */ 1633a28e824fSDouglas Anderson if (nbits) 1634a28e824fSDouglas Anderson *len = DIV_ROUND_UP(nbits, 8); 1635a28e824fSDouglas Anderson 1636a28e824fSDouglas Anderson if (*len > max_len) { 1637a28e824fSDouglas Anderson kfree(buf); 1638a28e824fSDouglas Anderson return ERR_PTR(-ERANGE); 1639a28e824fSDouglas Anderson } 1640a28e824fSDouglas Anderson 1641a28e824fSDouglas Anderson return buf; 1642a28e824fSDouglas Anderson } 1643a28e824fSDouglas Anderson 1644a28e824fSDouglas Anderson /** 1645a28e824fSDouglas Anderson * nvmem_cell_read_variable_le_u32() - Read up to 32-bits of data as a little endian number. 1646a28e824fSDouglas Anderson * 1647a28e824fSDouglas Anderson * @dev: Device that requests the nvmem cell. 1648a28e824fSDouglas Anderson * @cell_id: Name of nvmem cell to read. 1649a28e824fSDouglas Anderson * @val: pointer to output value. 1650a28e824fSDouglas Anderson * 1651a28e824fSDouglas Anderson * Return: 0 on success or negative errno. 1652a28e824fSDouglas Anderson */ 1653a28e824fSDouglas Anderson int nvmem_cell_read_variable_le_u32(struct device *dev, const char *cell_id, 1654a28e824fSDouglas Anderson u32 *val) 1655a28e824fSDouglas Anderson { 1656a28e824fSDouglas Anderson size_t len; 1657a28e824fSDouglas Anderson u8 *buf; 1658a28e824fSDouglas Anderson int i; 1659a28e824fSDouglas Anderson 1660a28e824fSDouglas Anderson buf = nvmem_cell_read_variable_common(dev, cell_id, sizeof(*val), &len); 1661a28e824fSDouglas Anderson if (IS_ERR(buf)) 1662a28e824fSDouglas Anderson return PTR_ERR(buf); 1663a28e824fSDouglas Anderson 1664a28e824fSDouglas Anderson /* Copy w/ implicit endian conversion */ 1665a28e824fSDouglas Anderson *val = 0; 1666a28e824fSDouglas Anderson for (i = 0; i < len; i++) 1667a28e824fSDouglas Anderson *val |= buf[i] << (8 * i); 1668a28e824fSDouglas Anderson 1669a28e824fSDouglas Anderson kfree(buf); 1670a28e824fSDouglas Anderson 1671a28e824fSDouglas Anderson return 0; 1672a28e824fSDouglas Anderson } 1673a28e824fSDouglas Anderson EXPORT_SYMBOL_GPL(nvmem_cell_read_variable_le_u32); 1674a28e824fSDouglas Anderson 1675a28e824fSDouglas Anderson /** 1676a28e824fSDouglas Anderson * nvmem_cell_read_variable_le_u64() - Read up to 64-bits of data as a little endian number. 1677a28e824fSDouglas Anderson * 1678a28e824fSDouglas Anderson * @dev: Device that requests the nvmem cell. 1679a28e824fSDouglas Anderson * @cell_id: Name of nvmem cell to read. 1680a28e824fSDouglas Anderson * @val: pointer to output value. 1681a28e824fSDouglas Anderson * 1682a28e824fSDouglas Anderson * Return: 0 on success or negative errno. 1683a28e824fSDouglas Anderson */ 1684a28e824fSDouglas Anderson int nvmem_cell_read_variable_le_u64(struct device *dev, const char *cell_id, 1685a28e824fSDouglas Anderson u64 *val) 1686a28e824fSDouglas Anderson { 1687a28e824fSDouglas Anderson size_t len; 1688a28e824fSDouglas Anderson u8 *buf; 1689a28e824fSDouglas Anderson int i; 1690a28e824fSDouglas Anderson 1691a28e824fSDouglas Anderson buf = nvmem_cell_read_variable_common(dev, cell_id, sizeof(*val), &len); 1692a28e824fSDouglas Anderson if (IS_ERR(buf)) 1693a28e824fSDouglas Anderson return PTR_ERR(buf); 1694a28e824fSDouglas Anderson 1695a28e824fSDouglas Anderson /* Copy w/ implicit endian conversion */ 1696a28e824fSDouglas Anderson *val = 0; 1697a28e824fSDouglas Anderson for (i = 0; i < len; i++) 169855022fdeSColin Ian King *val |= (uint64_t)buf[i] << (8 * i); 1699a28e824fSDouglas Anderson 1700a28e824fSDouglas Anderson kfree(buf); 1701a28e824fSDouglas Anderson 1702a28e824fSDouglas Anderson return 0; 1703a28e824fSDouglas Anderson } 1704a28e824fSDouglas Anderson EXPORT_SYMBOL_GPL(nvmem_cell_read_variable_le_u64); 1705a28e824fSDouglas Anderson 17068b977c54SYangtao Li /** 1707e2a5402eSSrinivas Kandagatla * nvmem_device_cell_read() - Read a given nvmem device and cell 1708e2a5402eSSrinivas Kandagatla * 1709e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to read from. 1710e2a5402eSSrinivas Kandagatla * @info: nvmem cell info to be read. 1711e2a5402eSSrinivas Kandagatla * @buf: buffer pointer which will be populated on successful read. 1712e2a5402eSSrinivas Kandagatla * 1713e2a5402eSSrinivas Kandagatla * Return: length of successful bytes read on success and negative 1714e2a5402eSSrinivas Kandagatla * error code on error. 1715e2a5402eSSrinivas Kandagatla */ 1716e2a5402eSSrinivas Kandagatla ssize_t nvmem_device_cell_read(struct nvmem_device *nvmem, 1717e2a5402eSSrinivas Kandagatla struct nvmem_cell_info *info, void *buf) 1718e2a5402eSSrinivas Kandagatla { 1719e2a5402eSSrinivas Kandagatla struct nvmem_cell cell; 1720e2a5402eSSrinivas Kandagatla int rc; 1721e2a5402eSSrinivas Kandagatla ssize_t len; 1722e2a5402eSSrinivas Kandagatla 1723795ddd18SSrinivas Kandagatla if (!nvmem) 1724e2a5402eSSrinivas Kandagatla return -EINVAL; 1725e2a5402eSSrinivas Kandagatla 1726fc9eec4dSVadym Kochan rc = nvmem_cell_info_to_nvmem_cell_nodup(nvmem, info, &cell); 1727287980e4SArnd Bergmann if (rc) 1728e2a5402eSSrinivas Kandagatla return rc; 1729e2a5402eSSrinivas Kandagatla 1730e2a5402eSSrinivas Kandagatla rc = __nvmem_cell_read(nvmem, &cell, buf, &len); 1731287980e4SArnd Bergmann if (rc) 1732e2a5402eSSrinivas Kandagatla return rc; 1733e2a5402eSSrinivas Kandagatla 1734e2a5402eSSrinivas Kandagatla return len; 1735e2a5402eSSrinivas Kandagatla } 1736e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_cell_read); 1737e2a5402eSSrinivas Kandagatla 1738e2a5402eSSrinivas Kandagatla /** 1739e2a5402eSSrinivas Kandagatla * nvmem_device_cell_write() - Write cell to a given nvmem device 1740e2a5402eSSrinivas Kandagatla * 1741e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to be written to. 174229143268SVivek Gautam * @info: nvmem cell info to be written. 1743e2a5402eSSrinivas Kandagatla * @buf: buffer to be written to cell. 1744e2a5402eSSrinivas Kandagatla * 1745e2a5402eSSrinivas Kandagatla * Return: length of bytes written or negative error code on failure. 174648f63a2cSBartosz Golaszewski */ 1747e2a5402eSSrinivas Kandagatla int nvmem_device_cell_write(struct nvmem_device *nvmem, 1748e2a5402eSSrinivas Kandagatla struct nvmem_cell_info *info, void *buf) 1749e2a5402eSSrinivas Kandagatla { 1750e2a5402eSSrinivas Kandagatla struct nvmem_cell cell; 1751e2a5402eSSrinivas Kandagatla int rc; 1752e2a5402eSSrinivas Kandagatla 1753795ddd18SSrinivas Kandagatla if (!nvmem) 1754e2a5402eSSrinivas Kandagatla return -EINVAL; 1755e2a5402eSSrinivas Kandagatla 1756fc9eec4dSVadym Kochan rc = nvmem_cell_info_to_nvmem_cell_nodup(nvmem, info, &cell); 1757287980e4SArnd Bergmann if (rc) 1758e2a5402eSSrinivas Kandagatla return rc; 1759e2a5402eSSrinivas Kandagatla 1760e2a5402eSSrinivas Kandagatla return nvmem_cell_write(&cell, buf, cell.bytes); 1761e2a5402eSSrinivas Kandagatla } 1762e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_cell_write); 1763e2a5402eSSrinivas Kandagatla 1764e2a5402eSSrinivas Kandagatla /** 1765e2a5402eSSrinivas Kandagatla * nvmem_device_read() - Read from a given nvmem device 1766e2a5402eSSrinivas Kandagatla * 1767e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to read from. 1768e2a5402eSSrinivas Kandagatla * @offset: offset in nvmem device. 1769e2a5402eSSrinivas Kandagatla * @bytes: number of bytes to read. 1770e2a5402eSSrinivas Kandagatla * @buf: buffer pointer which will be populated on successful read. 1771e2a5402eSSrinivas Kandagatla * 1772e2a5402eSSrinivas Kandagatla * Return: length of successful bytes read on success and negative 1773e2a5402eSSrinivas Kandagatla * error code on error. 1774e2a5402eSSrinivas Kandagatla */ 1775e2a5402eSSrinivas Kandagatla int nvmem_device_read(struct nvmem_device *nvmem, 1776e2a5402eSSrinivas Kandagatla unsigned int offset, 1777e2a5402eSSrinivas Kandagatla size_t bytes, void *buf) 1778e2a5402eSSrinivas Kandagatla { 1779e2a5402eSSrinivas Kandagatla int rc; 1780e2a5402eSSrinivas Kandagatla 1781795ddd18SSrinivas Kandagatla if (!nvmem) 1782e2a5402eSSrinivas Kandagatla return -EINVAL; 1783e2a5402eSSrinivas Kandagatla 1784795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, offset, buf, bytes); 1785e2a5402eSSrinivas Kandagatla 1786287980e4SArnd Bergmann if (rc) 1787e2a5402eSSrinivas Kandagatla return rc; 1788e2a5402eSSrinivas Kandagatla 1789e2a5402eSSrinivas Kandagatla return bytes; 1790e2a5402eSSrinivas Kandagatla } 1791e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_read); 1792e2a5402eSSrinivas Kandagatla 1793e2a5402eSSrinivas Kandagatla /** 1794e2a5402eSSrinivas Kandagatla * nvmem_device_write() - Write cell to a given nvmem device 1795e2a5402eSSrinivas Kandagatla * 1796e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to be written to. 1797e2a5402eSSrinivas Kandagatla * @offset: offset in nvmem device. 1798e2a5402eSSrinivas Kandagatla * @bytes: number of bytes to write. 1799e2a5402eSSrinivas Kandagatla * @buf: buffer to be written. 1800e2a5402eSSrinivas Kandagatla * 1801e2a5402eSSrinivas Kandagatla * Return: length of bytes written or negative error code on failure. 180248f63a2cSBartosz Golaszewski */ 1803e2a5402eSSrinivas Kandagatla int nvmem_device_write(struct nvmem_device *nvmem, 1804e2a5402eSSrinivas Kandagatla unsigned int offset, 1805e2a5402eSSrinivas Kandagatla size_t bytes, void *buf) 1806e2a5402eSSrinivas Kandagatla { 1807e2a5402eSSrinivas Kandagatla int rc; 1808e2a5402eSSrinivas Kandagatla 1809795ddd18SSrinivas Kandagatla if (!nvmem) 1810e2a5402eSSrinivas Kandagatla return -EINVAL; 1811e2a5402eSSrinivas Kandagatla 1812795ddd18SSrinivas Kandagatla rc = nvmem_reg_write(nvmem, offset, buf, bytes); 1813e2a5402eSSrinivas Kandagatla 1814287980e4SArnd Bergmann if (rc) 1815e2a5402eSSrinivas Kandagatla return rc; 1816e2a5402eSSrinivas Kandagatla 1817e2a5402eSSrinivas Kandagatla 1818e2a5402eSSrinivas Kandagatla return bytes; 1819e2a5402eSSrinivas Kandagatla } 1820e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_write); 1821e2a5402eSSrinivas Kandagatla 1822d7b9fd16SBartosz Golaszewski /** 1823b985f4cbSBartosz Golaszewski * nvmem_add_cell_table() - register a table of cell info entries 1824b985f4cbSBartosz Golaszewski * 1825b985f4cbSBartosz Golaszewski * @table: table of cell info entries 1826b985f4cbSBartosz Golaszewski */ 1827b985f4cbSBartosz Golaszewski void nvmem_add_cell_table(struct nvmem_cell_table *table) 1828b985f4cbSBartosz Golaszewski { 1829b985f4cbSBartosz Golaszewski mutex_lock(&nvmem_cell_mutex); 1830b985f4cbSBartosz Golaszewski list_add_tail(&table->node, &nvmem_cell_tables); 1831b985f4cbSBartosz Golaszewski mutex_unlock(&nvmem_cell_mutex); 1832b985f4cbSBartosz Golaszewski } 1833b985f4cbSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_add_cell_table); 1834b985f4cbSBartosz Golaszewski 1835b985f4cbSBartosz Golaszewski /** 1836b985f4cbSBartosz Golaszewski * nvmem_del_cell_table() - remove a previously registered cell info table 1837b985f4cbSBartosz Golaszewski * 1838b985f4cbSBartosz Golaszewski * @table: table of cell info entries 1839b985f4cbSBartosz Golaszewski */ 1840b985f4cbSBartosz Golaszewski void nvmem_del_cell_table(struct nvmem_cell_table *table) 1841b985f4cbSBartosz Golaszewski { 1842b985f4cbSBartosz Golaszewski mutex_lock(&nvmem_cell_mutex); 1843b985f4cbSBartosz Golaszewski list_del(&table->node); 1844b985f4cbSBartosz Golaszewski mutex_unlock(&nvmem_cell_mutex); 1845b985f4cbSBartosz Golaszewski } 1846b985f4cbSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_del_cell_table); 1847b985f4cbSBartosz Golaszewski 1848b985f4cbSBartosz Golaszewski /** 1849506157beSBartosz Golaszewski * nvmem_add_cell_lookups() - register a list of cell lookup entries 1850506157beSBartosz Golaszewski * 1851506157beSBartosz Golaszewski * @entries: array of cell lookup entries 1852506157beSBartosz Golaszewski * @nentries: number of cell lookup entries in the array 1853506157beSBartosz Golaszewski */ 1854506157beSBartosz Golaszewski void nvmem_add_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries) 1855506157beSBartosz Golaszewski { 1856506157beSBartosz Golaszewski int i; 1857506157beSBartosz Golaszewski 1858506157beSBartosz Golaszewski mutex_lock(&nvmem_lookup_mutex); 1859506157beSBartosz Golaszewski for (i = 0; i < nentries; i++) 1860506157beSBartosz Golaszewski list_add_tail(&entries[i].node, &nvmem_lookup_list); 1861506157beSBartosz Golaszewski mutex_unlock(&nvmem_lookup_mutex); 1862506157beSBartosz Golaszewski } 1863506157beSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_add_cell_lookups); 1864506157beSBartosz Golaszewski 1865506157beSBartosz Golaszewski /** 1866506157beSBartosz Golaszewski * nvmem_del_cell_lookups() - remove a list of previously added cell lookup 1867506157beSBartosz Golaszewski * entries 1868506157beSBartosz Golaszewski * 1869506157beSBartosz Golaszewski * @entries: array of cell lookup entries 1870506157beSBartosz Golaszewski * @nentries: number of cell lookup entries in the array 1871506157beSBartosz Golaszewski */ 1872506157beSBartosz Golaszewski void nvmem_del_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries) 1873506157beSBartosz Golaszewski { 1874506157beSBartosz Golaszewski int i; 1875506157beSBartosz Golaszewski 1876506157beSBartosz Golaszewski mutex_lock(&nvmem_lookup_mutex); 1877506157beSBartosz Golaszewski for (i = 0; i < nentries; i++) 1878506157beSBartosz Golaszewski list_del(&entries[i].node); 1879506157beSBartosz Golaszewski mutex_unlock(&nvmem_lookup_mutex); 1880506157beSBartosz Golaszewski } 1881506157beSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_del_cell_lookups); 1882506157beSBartosz Golaszewski 1883506157beSBartosz Golaszewski /** 1884d7b9fd16SBartosz Golaszewski * nvmem_dev_name() - Get the name of a given nvmem device. 1885d7b9fd16SBartosz Golaszewski * 1886d7b9fd16SBartosz Golaszewski * @nvmem: nvmem device. 1887d7b9fd16SBartosz Golaszewski * 1888d7b9fd16SBartosz Golaszewski * Return: name of the nvmem device. 1889d7b9fd16SBartosz Golaszewski */ 1890d7b9fd16SBartosz Golaszewski const char *nvmem_dev_name(struct nvmem_device *nvmem) 1891d7b9fd16SBartosz Golaszewski { 1892d7b9fd16SBartosz Golaszewski return dev_name(&nvmem->dev); 1893d7b9fd16SBartosz Golaszewski } 1894d7b9fd16SBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_dev_name); 1895d7b9fd16SBartosz Golaszewski 1896eace75cfSSrinivas Kandagatla static int __init nvmem_init(void) 1897eace75cfSSrinivas Kandagatla { 1898eace75cfSSrinivas Kandagatla return bus_register(&nvmem_bus_type); 1899eace75cfSSrinivas Kandagatla } 1900eace75cfSSrinivas Kandagatla 1901eace75cfSSrinivas Kandagatla static void __exit nvmem_exit(void) 1902eace75cfSSrinivas Kandagatla { 1903eace75cfSSrinivas Kandagatla bus_unregister(&nvmem_bus_type); 1904eace75cfSSrinivas Kandagatla } 1905eace75cfSSrinivas Kandagatla 1906eace75cfSSrinivas Kandagatla subsys_initcall(nvmem_init); 1907eace75cfSSrinivas Kandagatla module_exit(nvmem_exit); 1908eace75cfSSrinivas Kandagatla 1909eace75cfSSrinivas Kandagatla MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org"); 1910eace75cfSSrinivas Kandagatla MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com"); 1911eace75cfSSrinivas Kandagatla MODULE_DESCRIPTION("nvmem Driver Core"); 1912eace75cfSSrinivas Kandagatla MODULE_LICENSE("GPL v2"); 1913