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; 3784400305SSrinivas Kandagatla nvmem_reg_read_t reg_read; 3884400305SSrinivas Kandagatla nvmem_reg_write_t reg_write; 3984400305SSrinivas Kandagatla struct gpio_desc *wp_gpio; 4084400305SSrinivas Kandagatla void *priv; 4184400305SSrinivas Kandagatla }; 4284400305SSrinivas Kandagatla 4384400305SSrinivas Kandagatla #define to_nvmem_device(d) container_of(d, struct nvmem_device, dev) 4484400305SSrinivas Kandagatla 4584400305SSrinivas Kandagatla #define FLAG_COMPAT BIT(0) 46b6c217abSAndrew Lunn 47eace75cfSSrinivas Kandagatla struct nvmem_cell { 48eace75cfSSrinivas Kandagatla const char *name; 49eace75cfSSrinivas Kandagatla int offset; 50eace75cfSSrinivas Kandagatla int bytes; 51eace75cfSSrinivas Kandagatla int bit_offset; 52eace75cfSSrinivas Kandagatla int nbits; 530749aa25SSrinivas Kandagatla struct device_node *np; 54eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem; 55eace75cfSSrinivas Kandagatla struct list_head node; 56eace75cfSSrinivas Kandagatla }; 57eace75cfSSrinivas Kandagatla 58eace75cfSSrinivas Kandagatla static DEFINE_MUTEX(nvmem_mutex); 59eace75cfSSrinivas Kandagatla static DEFINE_IDA(nvmem_ida); 60eace75cfSSrinivas Kandagatla 61b985f4cbSBartosz Golaszewski static DEFINE_MUTEX(nvmem_cell_mutex); 62b985f4cbSBartosz Golaszewski static LIST_HEAD(nvmem_cell_tables); 63b985f4cbSBartosz Golaszewski 64506157beSBartosz Golaszewski static DEFINE_MUTEX(nvmem_lookup_mutex); 65506157beSBartosz Golaszewski static LIST_HEAD(nvmem_lookup_list); 66506157beSBartosz Golaszewski 67bee1138bSBartosz Golaszewski static BLOCKING_NOTIFIER_HEAD(nvmem_notifier); 68bee1138bSBartosz Golaszewski 69b96fc541SMichael Auchter static int nvmem_reg_read(struct nvmem_device *nvmem, unsigned int offset, 70b96fc541SMichael Auchter void *val, size_t bytes) 71b96fc541SMichael Auchter { 72b96fc541SMichael Auchter if (nvmem->reg_read) 73b96fc541SMichael Auchter return nvmem->reg_read(nvmem->priv, offset, val, bytes); 74b96fc541SMichael Auchter 75b96fc541SMichael Auchter return -EINVAL; 76b96fc541SMichael Auchter } 77b96fc541SMichael Auchter 78b96fc541SMichael Auchter static int nvmem_reg_write(struct nvmem_device *nvmem, unsigned int offset, 79b96fc541SMichael Auchter void *val, size_t bytes) 80b96fc541SMichael Auchter { 81b96fc541SMichael Auchter int ret; 82b96fc541SMichael Auchter 83b96fc541SMichael Auchter if (nvmem->reg_write) { 84b96fc541SMichael Auchter gpiod_set_value_cansleep(nvmem->wp_gpio, 0); 85b96fc541SMichael Auchter ret = nvmem->reg_write(nvmem->priv, offset, val, bytes); 86b96fc541SMichael Auchter gpiod_set_value_cansleep(nvmem->wp_gpio, 1); 87b96fc541SMichael Auchter return ret; 88b96fc541SMichael Auchter } 89b96fc541SMichael Auchter 90b96fc541SMichael Auchter return -EINVAL; 91b96fc541SMichael Auchter } 92b96fc541SMichael Auchter 9384400305SSrinivas Kandagatla #ifdef CONFIG_NVMEM_SYSFS 9484400305SSrinivas Kandagatla static const char * const nvmem_type_str[] = { 9584400305SSrinivas Kandagatla [NVMEM_TYPE_UNKNOWN] = "Unknown", 9684400305SSrinivas Kandagatla [NVMEM_TYPE_EEPROM] = "EEPROM", 9784400305SSrinivas Kandagatla [NVMEM_TYPE_OTP] = "OTP", 9884400305SSrinivas Kandagatla [NVMEM_TYPE_BATTERY_BACKED] = "Battery backed", 9984400305SSrinivas Kandagatla }; 10084400305SSrinivas Kandagatla 10184400305SSrinivas Kandagatla #ifdef CONFIG_DEBUG_LOCK_ALLOC 10284400305SSrinivas Kandagatla static struct lock_class_key eeprom_lock_key; 10384400305SSrinivas Kandagatla #endif 10484400305SSrinivas Kandagatla 10584400305SSrinivas Kandagatla static ssize_t type_show(struct device *dev, 10684400305SSrinivas Kandagatla struct device_attribute *attr, char *buf) 10784400305SSrinivas Kandagatla { 10884400305SSrinivas Kandagatla struct nvmem_device *nvmem = to_nvmem_device(dev); 10984400305SSrinivas Kandagatla 11084400305SSrinivas Kandagatla return sprintf(buf, "%s\n", nvmem_type_str[nvmem->type]); 11184400305SSrinivas Kandagatla } 11284400305SSrinivas Kandagatla 11384400305SSrinivas Kandagatla static DEVICE_ATTR_RO(type); 11484400305SSrinivas Kandagatla 11584400305SSrinivas Kandagatla static struct attribute *nvmem_attrs[] = { 11684400305SSrinivas Kandagatla &dev_attr_type.attr, 11784400305SSrinivas Kandagatla NULL, 11884400305SSrinivas Kandagatla }; 11984400305SSrinivas Kandagatla 12084400305SSrinivas Kandagatla static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj, 12184400305SSrinivas Kandagatla struct bin_attribute *attr, char *buf, 12284400305SSrinivas Kandagatla loff_t pos, size_t count) 12384400305SSrinivas Kandagatla { 12484400305SSrinivas Kandagatla struct device *dev; 12584400305SSrinivas Kandagatla struct nvmem_device *nvmem; 12684400305SSrinivas Kandagatla int rc; 12784400305SSrinivas Kandagatla 12884400305SSrinivas Kandagatla if (attr->private) 12984400305SSrinivas Kandagatla dev = attr->private; 13084400305SSrinivas Kandagatla else 13128371cc6STian Tao dev = kobj_to_dev(kobj); 13284400305SSrinivas Kandagatla nvmem = to_nvmem_device(dev); 13384400305SSrinivas Kandagatla 13484400305SSrinivas Kandagatla /* Stop the user from reading */ 13584400305SSrinivas Kandagatla if (pos >= nvmem->size) 13684400305SSrinivas Kandagatla return 0; 13784400305SSrinivas Kandagatla 13883566715SDouglas Anderson if (!IS_ALIGNED(pos, nvmem->stride)) 13983566715SDouglas Anderson return -EINVAL; 14083566715SDouglas Anderson 14184400305SSrinivas Kandagatla if (count < nvmem->word_size) 14284400305SSrinivas Kandagatla return -EINVAL; 14384400305SSrinivas Kandagatla 14484400305SSrinivas Kandagatla if (pos + count > nvmem->size) 14584400305SSrinivas Kandagatla count = nvmem->size - pos; 14684400305SSrinivas Kandagatla 14784400305SSrinivas Kandagatla count = round_down(count, nvmem->word_size); 14884400305SSrinivas Kandagatla 14984400305SSrinivas Kandagatla if (!nvmem->reg_read) 15084400305SSrinivas Kandagatla return -EPERM; 15184400305SSrinivas Kandagatla 152b96fc541SMichael Auchter rc = nvmem_reg_read(nvmem, pos, buf, count); 15384400305SSrinivas Kandagatla 15484400305SSrinivas Kandagatla if (rc) 15584400305SSrinivas Kandagatla return rc; 15684400305SSrinivas Kandagatla 15784400305SSrinivas Kandagatla return count; 15884400305SSrinivas Kandagatla } 15984400305SSrinivas Kandagatla 16084400305SSrinivas Kandagatla static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj, 16184400305SSrinivas Kandagatla struct bin_attribute *attr, char *buf, 16284400305SSrinivas Kandagatla loff_t pos, size_t count) 16384400305SSrinivas Kandagatla { 16484400305SSrinivas Kandagatla struct device *dev; 16584400305SSrinivas Kandagatla struct nvmem_device *nvmem; 16684400305SSrinivas Kandagatla int rc; 16784400305SSrinivas Kandagatla 16884400305SSrinivas Kandagatla if (attr->private) 16984400305SSrinivas Kandagatla dev = attr->private; 17084400305SSrinivas Kandagatla else 17128371cc6STian Tao dev = kobj_to_dev(kobj); 17284400305SSrinivas Kandagatla nvmem = to_nvmem_device(dev); 17384400305SSrinivas Kandagatla 17484400305SSrinivas Kandagatla /* Stop the user from writing */ 17584400305SSrinivas Kandagatla if (pos >= nvmem->size) 17684400305SSrinivas Kandagatla return -EFBIG; 17784400305SSrinivas Kandagatla 17883566715SDouglas Anderson if (!IS_ALIGNED(pos, nvmem->stride)) 17983566715SDouglas Anderson return -EINVAL; 18083566715SDouglas Anderson 18184400305SSrinivas Kandagatla if (count < nvmem->word_size) 18284400305SSrinivas Kandagatla return -EINVAL; 18384400305SSrinivas Kandagatla 18484400305SSrinivas Kandagatla if (pos + count > nvmem->size) 18584400305SSrinivas Kandagatla count = nvmem->size - pos; 18684400305SSrinivas Kandagatla 18784400305SSrinivas Kandagatla count = round_down(count, nvmem->word_size); 18884400305SSrinivas Kandagatla 18984400305SSrinivas Kandagatla if (!nvmem->reg_write) 19084400305SSrinivas Kandagatla return -EPERM; 19184400305SSrinivas Kandagatla 192b96fc541SMichael Auchter rc = nvmem_reg_write(nvmem, pos, buf, count); 19384400305SSrinivas Kandagatla 19484400305SSrinivas Kandagatla if (rc) 19584400305SSrinivas Kandagatla return rc; 19684400305SSrinivas Kandagatla 19784400305SSrinivas Kandagatla return count; 19884400305SSrinivas Kandagatla } 19984400305SSrinivas Kandagatla 2002a4542e5SSrinivas Kandagatla static umode_t nvmem_bin_attr_get_umode(struct nvmem_device *nvmem) 20184400305SSrinivas Kandagatla { 20284400305SSrinivas Kandagatla umode_t mode = 0400; 20384400305SSrinivas Kandagatla 20484400305SSrinivas Kandagatla if (!nvmem->root_only) 20584400305SSrinivas Kandagatla mode |= 0044; 20684400305SSrinivas Kandagatla 20784400305SSrinivas Kandagatla if (!nvmem->read_only) 20884400305SSrinivas Kandagatla mode |= 0200; 20984400305SSrinivas Kandagatla 21084400305SSrinivas Kandagatla if (!nvmem->reg_write) 21184400305SSrinivas Kandagatla mode &= ~0200; 21284400305SSrinivas Kandagatla 21384400305SSrinivas Kandagatla if (!nvmem->reg_read) 21484400305SSrinivas Kandagatla mode &= ~0444; 21584400305SSrinivas Kandagatla 21684400305SSrinivas Kandagatla return mode; 21784400305SSrinivas Kandagatla } 21884400305SSrinivas Kandagatla 2192a4542e5SSrinivas Kandagatla static umode_t nvmem_bin_attr_is_visible(struct kobject *kobj, 2202a4542e5SSrinivas Kandagatla struct bin_attribute *attr, int i) 2212a4542e5SSrinivas Kandagatla { 22228371cc6STian Tao struct device *dev = kobj_to_dev(kobj); 2232a4542e5SSrinivas Kandagatla struct nvmem_device *nvmem = to_nvmem_device(dev); 2242a4542e5SSrinivas Kandagatla 2252a4542e5SSrinivas Kandagatla return nvmem_bin_attr_get_umode(nvmem); 2262a4542e5SSrinivas Kandagatla } 2272a4542e5SSrinivas Kandagatla 22884400305SSrinivas Kandagatla /* default read/write permissions */ 22984400305SSrinivas Kandagatla static struct bin_attribute bin_attr_rw_nvmem = { 23084400305SSrinivas Kandagatla .attr = { 23184400305SSrinivas Kandagatla .name = "nvmem", 23284400305SSrinivas Kandagatla .mode = 0644, 23384400305SSrinivas Kandagatla }, 23484400305SSrinivas Kandagatla .read = bin_attr_nvmem_read, 23584400305SSrinivas Kandagatla .write = bin_attr_nvmem_write, 23684400305SSrinivas Kandagatla }; 23784400305SSrinivas Kandagatla 23884400305SSrinivas Kandagatla static struct bin_attribute *nvmem_bin_attributes[] = { 23984400305SSrinivas Kandagatla &bin_attr_rw_nvmem, 24084400305SSrinivas Kandagatla NULL, 24184400305SSrinivas Kandagatla }; 24284400305SSrinivas Kandagatla 24384400305SSrinivas Kandagatla static const struct attribute_group nvmem_bin_group = { 24484400305SSrinivas Kandagatla .bin_attrs = nvmem_bin_attributes, 24584400305SSrinivas Kandagatla .attrs = nvmem_attrs, 24684400305SSrinivas Kandagatla .is_bin_visible = nvmem_bin_attr_is_visible, 24784400305SSrinivas Kandagatla }; 24884400305SSrinivas Kandagatla 24984400305SSrinivas Kandagatla static const struct attribute_group *nvmem_dev_groups[] = { 25084400305SSrinivas Kandagatla &nvmem_bin_group, 25184400305SSrinivas Kandagatla NULL, 25284400305SSrinivas Kandagatla }; 25384400305SSrinivas Kandagatla 2542a4542e5SSrinivas Kandagatla static struct bin_attribute bin_attr_nvmem_eeprom_compat = { 25584400305SSrinivas Kandagatla .attr = { 2562a4542e5SSrinivas Kandagatla .name = "eeprom", 25784400305SSrinivas Kandagatla }, 25884400305SSrinivas Kandagatla .read = bin_attr_nvmem_read, 25984400305SSrinivas Kandagatla .write = bin_attr_nvmem_write, 26084400305SSrinivas Kandagatla }; 26184400305SSrinivas Kandagatla 26284400305SSrinivas Kandagatla /* 26384400305SSrinivas Kandagatla * nvmem_setup_compat() - Create an additional binary entry in 26484400305SSrinivas Kandagatla * drivers sys directory, to be backwards compatible with the older 26584400305SSrinivas Kandagatla * drivers/misc/eeprom drivers. 26684400305SSrinivas Kandagatla */ 26784400305SSrinivas Kandagatla static int nvmem_sysfs_setup_compat(struct nvmem_device *nvmem, 26884400305SSrinivas Kandagatla const struct nvmem_config *config) 26984400305SSrinivas Kandagatla { 27084400305SSrinivas Kandagatla int rval; 27184400305SSrinivas Kandagatla 27284400305SSrinivas Kandagatla if (!config->compat) 27384400305SSrinivas Kandagatla return 0; 27484400305SSrinivas Kandagatla 27584400305SSrinivas Kandagatla if (!config->base_dev) 27684400305SSrinivas Kandagatla return -EINVAL; 27784400305SSrinivas Kandagatla 2782a4542e5SSrinivas Kandagatla nvmem->eeprom = bin_attr_nvmem_eeprom_compat; 2792a4542e5SSrinivas Kandagatla nvmem->eeprom.attr.mode = nvmem_bin_attr_get_umode(nvmem); 28084400305SSrinivas Kandagatla nvmem->eeprom.size = nvmem->size; 28184400305SSrinivas Kandagatla #ifdef CONFIG_DEBUG_LOCK_ALLOC 28284400305SSrinivas Kandagatla nvmem->eeprom.attr.key = &eeprom_lock_key; 28384400305SSrinivas Kandagatla #endif 28484400305SSrinivas Kandagatla nvmem->eeprom.private = &nvmem->dev; 28584400305SSrinivas Kandagatla nvmem->base_dev = config->base_dev; 28684400305SSrinivas Kandagatla 28784400305SSrinivas Kandagatla rval = device_create_bin_file(nvmem->base_dev, &nvmem->eeprom); 28884400305SSrinivas Kandagatla if (rval) { 28984400305SSrinivas Kandagatla dev_err(&nvmem->dev, 29084400305SSrinivas Kandagatla "Failed to create eeprom binary file %d\n", rval); 29184400305SSrinivas Kandagatla return rval; 29284400305SSrinivas Kandagatla } 29384400305SSrinivas Kandagatla 29484400305SSrinivas Kandagatla nvmem->flags |= FLAG_COMPAT; 29584400305SSrinivas Kandagatla 29684400305SSrinivas Kandagatla return 0; 29784400305SSrinivas Kandagatla } 29884400305SSrinivas Kandagatla 29984400305SSrinivas Kandagatla static void nvmem_sysfs_remove_compat(struct nvmem_device *nvmem, 30084400305SSrinivas Kandagatla const struct nvmem_config *config) 30184400305SSrinivas Kandagatla { 30284400305SSrinivas Kandagatla if (config->compat) 30384400305SSrinivas Kandagatla device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); 30484400305SSrinivas Kandagatla } 30584400305SSrinivas Kandagatla 30684400305SSrinivas Kandagatla #else /* CONFIG_NVMEM_SYSFS */ 30784400305SSrinivas Kandagatla 30884400305SSrinivas Kandagatla static int nvmem_sysfs_setup_compat(struct nvmem_device *nvmem, 30984400305SSrinivas Kandagatla const struct nvmem_config *config) 31084400305SSrinivas Kandagatla { 31184400305SSrinivas Kandagatla return -ENOSYS; 31284400305SSrinivas Kandagatla } 31384400305SSrinivas Kandagatla static void nvmem_sysfs_remove_compat(struct nvmem_device *nvmem, 31484400305SSrinivas Kandagatla const struct nvmem_config *config) 31584400305SSrinivas Kandagatla { 31684400305SSrinivas Kandagatla } 31784400305SSrinivas Kandagatla 31884400305SSrinivas Kandagatla #endif /* CONFIG_NVMEM_SYSFS */ 319a8b44d5dSAndy Shevchenko 320eace75cfSSrinivas Kandagatla static void nvmem_release(struct device *dev) 321eace75cfSSrinivas Kandagatla { 322eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem = to_nvmem_device(dev); 323eace75cfSSrinivas Kandagatla 3241eb51d6aSBartosz Golaszewski ida_free(&nvmem_ida, nvmem->id); 325a9c3766cSKhouloud Touil gpiod_put(nvmem->wp_gpio); 326eace75cfSSrinivas Kandagatla kfree(nvmem); 327eace75cfSSrinivas Kandagatla } 328eace75cfSSrinivas Kandagatla 329eace75cfSSrinivas Kandagatla static const struct device_type nvmem_provider_type = { 330eace75cfSSrinivas Kandagatla .release = nvmem_release, 331eace75cfSSrinivas Kandagatla }; 332eace75cfSSrinivas Kandagatla 333eace75cfSSrinivas Kandagatla static struct bus_type nvmem_bus_type = { 334eace75cfSSrinivas Kandagatla .name = "nvmem", 335eace75cfSSrinivas Kandagatla }; 336eace75cfSSrinivas Kandagatla 337eace75cfSSrinivas Kandagatla static void nvmem_cell_drop(struct nvmem_cell *cell) 338eace75cfSSrinivas Kandagatla { 339bee1138bSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_REMOVE, cell); 340c7235ee3SBartosz Golaszewski mutex_lock(&nvmem_mutex); 341eace75cfSSrinivas Kandagatla list_del(&cell->node); 342c7235ee3SBartosz Golaszewski mutex_unlock(&nvmem_mutex); 3430749aa25SSrinivas Kandagatla of_node_put(cell->np); 34416bb7abcSBitan Biswas kfree_const(cell->name); 345eace75cfSSrinivas Kandagatla kfree(cell); 346eace75cfSSrinivas Kandagatla } 347eace75cfSSrinivas Kandagatla 348eace75cfSSrinivas Kandagatla static void nvmem_device_remove_all_cells(const struct nvmem_device *nvmem) 349eace75cfSSrinivas Kandagatla { 3501852183eSBartosz Golaszewski struct nvmem_cell *cell, *p; 351eace75cfSSrinivas Kandagatla 352c7235ee3SBartosz Golaszewski list_for_each_entry_safe(cell, p, &nvmem->cells, node) 353eace75cfSSrinivas Kandagatla nvmem_cell_drop(cell); 354eace75cfSSrinivas Kandagatla } 355eace75cfSSrinivas Kandagatla 356eace75cfSSrinivas Kandagatla static void nvmem_cell_add(struct nvmem_cell *cell) 357eace75cfSSrinivas Kandagatla { 358c7235ee3SBartosz Golaszewski mutex_lock(&nvmem_mutex); 359c7235ee3SBartosz Golaszewski list_add_tail(&cell->node, &cell->nvmem->cells); 360c7235ee3SBartosz Golaszewski mutex_unlock(&nvmem_mutex); 361bee1138bSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_ADD, cell); 362eace75cfSSrinivas Kandagatla } 363eace75cfSSrinivas Kandagatla 364*fc9eec4dSVadym Kochan static int nvmem_cell_info_to_nvmem_cell_nodup(struct nvmem_device *nvmem, 365eace75cfSSrinivas Kandagatla const struct nvmem_cell_info *info, 366eace75cfSSrinivas Kandagatla struct nvmem_cell *cell) 367eace75cfSSrinivas Kandagatla { 368eace75cfSSrinivas Kandagatla cell->nvmem = nvmem; 369eace75cfSSrinivas Kandagatla cell->offset = info->offset; 370eace75cfSSrinivas Kandagatla cell->bytes = info->bytes; 371*fc9eec4dSVadym Kochan cell->name = info->name; 372eace75cfSSrinivas Kandagatla 373eace75cfSSrinivas Kandagatla cell->bit_offset = info->bit_offset; 374eace75cfSSrinivas Kandagatla cell->nbits = info->nbits; 375eace75cfSSrinivas Kandagatla 376eace75cfSSrinivas Kandagatla if (cell->nbits) 377eace75cfSSrinivas Kandagatla cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset, 378eace75cfSSrinivas Kandagatla BITS_PER_BYTE); 379eace75cfSSrinivas Kandagatla 380eace75cfSSrinivas Kandagatla if (!IS_ALIGNED(cell->offset, nvmem->stride)) { 381eace75cfSSrinivas Kandagatla dev_err(&nvmem->dev, 382eace75cfSSrinivas Kandagatla "cell %s unaligned to nvmem stride %d\n", 383*fc9eec4dSVadym Kochan cell->name ?: "<unknown>", nvmem->stride); 384eace75cfSSrinivas Kandagatla return -EINVAL; 385eace75cfSSrinivas Kandagatla } 386eace75cfSSrinivas Kandagatla 387eace75cfSSrinivas Kandagatla return 0; 388eace75cfSSrinivas Kandagatla } 389eace75cfSSrinivas Kandagatla 390*fc9eec4dSVadym Kochan static int nvmem_cell_info_to_nvmem_cell(struct nvmem_device *nvmem, 391*fc9eec4dSVadym Kochan const struct nvmem_cell_info *info, 392*fc9eec4dSVadym Kochan struct nvmem_cell *cell) 393*fc9eec4dSVadym Kochan { 394*fc9eec4dSVadym Kochan int err; 395*fc9eec4dSVadym Kochan 396*fc9eec4dSVadym Kochan err = nvmem_cell_info_to_nvmem_cell_nodup(nvmem, info, cell); 397*fc9eec4dSVadym Kochan if (err) 398*fc9eec4dSVadym Kochan return err; 399*fc9eec4dSVadym Kochan 400*fc9eec4dSVadym Kochan cell->name = kstrdup_const(info->name, GFP_KERNEL); 401*fc9eec4dSVadym Kochan if (!cell->name) 402*fc9eec4dSVadym Kochan return -ENOMEM; 403*fc9eec4dSVadym Kochan 404*fc9eec4dSVadym Kochan return 0; 405*fc9eec4dSVadym Kochan } 406*fc9eec4dSVadym Kochan 407b3db17e4SAndrew Lunn /** 408b3db17e4SAndrew Lunn * nvmem_add_cells() - Add cell information to an nvmem device 409b3db17e4SAndrew Lunn * 410b3db17e4SAndrew Lunn * @nvmem: nvmem device to add cells to. 411b3db17e4SAndrew Lunn * @info: nvmem cell info to add to the device 412b3db17e4SAndrew Lunn * @ncells: number of cells in info 413b3db17e4SAndrew Lunn * 414b3db17e4SAndrew Lunn * Return: 0 or negative error code on failure. 415b3db17e4SAndrew Lunn */ 416ef92ab30SSrinivas Kandagatla static int nvmem_add_cells(struct nvmem_device *nvmem, 417b3db17e4SAndrew Lunn const struct nvmem_cell_info *info, 418b3db17e4SAndrew Lunn int ncells) 419eace75cfSSrinivas Kandagatla { 420eace75cfSSrinivas Kandagatla struct nvmem_cell **cells; 421eace75cfSSrinivas Kandagatla int i, rval; 422eace75cfSSrinivas Kandagatla 423b3db17e4SAndrew Lunn cells = kcalloc(ncells, sizeof(*cells), GFP_KERNEL); 424eace75cfSSrinivas Kandagatla if (!cells) 425eace75cfSSrinivas Kandagatla return -ENOMEM; 426eace75cfSSrinivas Kandagatla 427b3db17e4SAndrew Lunn for (i = 0; i < ncells; i++) { 428eace75cfSSrinivas Kandagatla cells[i] = kzalloc(sizeof(**cells), GFP_KERNEL); 429eace75cfSSrinivas Kandagatla if (!cells[i]) { 430eace75cfSSrinivas Kandagatla rval = -ENOMEM; 431eace75cfSSrinivas Kandagatla goto err; 432eace75cfSSrinivas Kandagatla } 433eace75cfSSrinivas Kandagatla 434eace75cfSSrinivas Kandagatla rval = nvmem_cell_info_to_nvmem_cell(nvmem, &info[i], cells[i]); 435287980e4SArnd Bergmann if (rval) { 436eace75cfSSrinivas Kandagatla kfree(cells[i]); 437eace75cfSSrinivas Kandagatla goto err; 438eace75cfSSrinivas Kandagatla } 439eace75cfSSrinivas Kandagatla 440eace75cfSSrinivas Kandagatla nvmem_cell_add(cells[i]); 441eace75cfSSrinivas Kandagatla } 442eace75cfSSrinivas Kandagatla 443eace75cfSSrinivas Kandagatla /* remove tmp array */ 444eace75cfSSrinivas Kandagatla kfree(cells); 445eace75cfSSrinivas Kandagatla 446eace75cfSSrinivas Kandagatla return 0; 447eace75cfSSrinivas Kandagatla err: 448dfdf1414SRasmus Villemoes while (i--) 449eace75cfSSrinivas Kandagatla nvmem_cell_drop(cells[i]); 450eace75cfSSrinivas Kandagatla 451dfdf1414SRasmus Villemoes kfree(cells); 452dfdf1414SRasmus Villemoes 453eace75cfSSrinivas Kandagatla return rval; 454eace75cfSSrinivas Kandagatla } 455eace75cfSSrinivas Kandagatla 456bee1138bSBartosz Golaszewski /** 457bee1138bSBartosz Golaszewski * nvmem_register_notifier() - Register a notifier block for nvmem events. 458bee1138bSBartosz Golaszewski * 459bee1138bSBartosz Golaszewski * @nb: notifier block to be called on nvmem events. 460bee1138bSBartosz Golaszewski * 461bee1138bSBartosz Golaszewski * Return: 0 on success, negative error number on failure. 462bee1138bSBartosz Golaszewski */ 463bee1138bSBartosz Golaszewski int nvmem_register_notifier(struct notifier_block *nb) 464bee1138bSBartosz Golaszewski { 465bee1138bSBartosz Golaszewski return blocking_notifier_chain_register(&nvmem_notifier, nb); 466bee1138bSBartosz Golaszewski } 467bee1138bSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_register_notifier); 468bee1138bSBartosz Golaszewski 469bee1138bSBartosz Golaszewski /** 470bee1138bSBartosz Golaszewski * nvmem_unregister_notifier() - Unregister a notifier block for nvmem events. 471bee1138bSBartosz Golaszewski * 472bee1138bSBartosz Golaszewski * @nb: notifier block to be unregistered. 473bee1138bSBartosz Golaszewski * 474bee1138bSBartosz Golaszewski * Return: 0 on success, negative error number on failure. 475bee1138bSBartosz Golaszewski */ 476bee1138bSBartosz Golaszewski int nvmem_unregister_notifier(struct notifier_block *nb) 477bee1138bSBartosz Golaszewski { 478bee1138bSBartosz Golaszewski return blocking_notifier_chain_unregister(&nvmem_notifier, nb); 479bee1138bSBartosz Golaszewski } 480bee1138bSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_unregister_notifier); 481bee1138bSBartosz Golaszewski 482b985f4cbSBartosz Golaszewski static int nvmem_add_cells_from_table(struct nvmem_device *nvmem) 483b985f4cbSBartosz Golaszewski { 484b985f4cbSBartosz Golaszewski const struct nvmem_cell_info *info; 485b985f4cbSBartosz Golaszewski struct nvmem_cell_table *table; 486b985f4cbSBartosz Golaszewski struct nvmem_cell *cell; 487b985f4cbSBartosz Golaszewski int rval = 0, i; 488b985f4cbSBartosz Golaszewski 489b985f4cbSBartosz Golaszewski mutex_lock(&nvmem_cell_mutex); 490b985f4cbSBartosz Golaszewski list_for_each_entry(table, &nvmem_cell_tables, node) { 491b985f4cbSBartosz Golaszewski if (strcmp(nvmem_dev_name(nvmem), table->nvmem_name) == 0) { 492b985f4cbSBartosz Golaszewski for (i = 0; i < table->ncells; i++) { 493b985f4cbSBartosz Golaszewski info = &table->cells[i]; 494b985f4cbSBartosz Golaszewski 495b985f4cbSBartosz Golaszewski cell = kzalloc(sizeof(*cell), GFP_KERNEL); 496b985f4cbSBartosz Golaszewski if (!cell) { 497b985f4cbSBartosz Golaszewski rval = -ENOMEM; 498b985f4cbSBartosz Golaszewski goto out; 499b985f4cbSBartosz Golaszewski } 500b985f4cbSBartosz Golaszewski 501b985f4cbSBartosz Golaszewski rval = nvmem_cell_info_to_nvmem_cell(nvmem, 502b985f4cbSBartosz Golaszewski info, 503b985f4cbSBartosz Golaszewski cell); 504b985f4cbSBartosz Golaszewski if (rval) { 505b985f4cbSBartosz Golaszewski kfree(cell); 506b985f4cbSBartosz Golaszewski goto out; 507b985f4cbSBartosz Golaszewski } 508b985f4cbSBartosz Golaszewski 509b985f4cbSBartosz Golaszewski nvmem_cell_add(cell); 510b985f4cbSBartosz Golaszewski } 511b985f4cbSBartosz Golaszewski } 512b985f4cbSBartosz Golaszewski } 513b985f4cbSBartosz Golaszewski 514b985f4cbSBartosz Golaszewski out: 515b985f4cbSBartosz Golaszewski mutex_unlock(&nvmem_cell_mutex); 516b985f4cbSBartosz Golaszewski return rval; 517b985f4cbSBartosz Golaszewski } 518b985f4cbSBartosz Golaszewski 519e888d445SBartosz Golaszewski static struct nvmem_cell * 520506157beSBartosz Golaszewski nvmem_find_cell_by_name(struct nvmem_device *nvmem, const char *cell_id) 521506157beSBartosz Golaszewski { 5221c832674SAlban Bedel struct nvmem_cell *iter, *cell = NULL; 523506157beSBartosz Golaszewski 524506157beSBartosz Golaszewski mutex_lock(&nvmem_mutex); 5251c832674SAlban Bedel list_for_each_entry(iter, &nvmem->cells, node) { 5261c832674SAlban Bedel if (strcmp(cell_id, iter->name) == 0) { 5271c832674SAlban Bedel cell = iter; 528506157beSBartosz Golaszewski break; 529506157beSBartosz Golaszewski } 5301c832674SAlban Bedel } 531506157beSBartosz Golaszewski mutex_unlock(&nvmem_mutex); 532506157beSBartosz Golaszewski 533506157beSBartosz Golaszewski return cell; 534506157beSBartosz Golaszewski } 535506157beSBartosz Golaszewski 536e888d445SBartosz Golaszewski static int nvmem_add_cells_from_of(struct nvmem_device *nvmem) 537e888d445SBartosz Golaszewski { 538e888d445SBartosz Golaszewski struct device_node *parent, *child; 539e888d445SBartosz Golaszewski struct device *dev = &nvmem->dev; 540e888d445SBartosz Golaszewski struct nvmem_cell *cell; 541e888d445SBartosz Golaszewski const __be32 *addr; 542e888d445SBartosz Golaszewski int len; 543e888d445SBartosz Golaszewski 544e888d445SBartosz Golaszewski parent = dev->of_node; 545e888d445SBartosz Golaszewski 546e888d445SBartosz Golaszewski for_each_child_of_node(parent, child) { 547e888d445SBartosz Golaszewski addr = of_get_property(child, "reg", &len); 548e888d445SBartosz Golaszewski if (!addr || (len < 2 * sizeof(u32))) { 549e888d445SBartosz Golaszewski dev_err(dev, "nvmem: invalid reg on %pOF\n", child); 550e888d445SBartosz Golaszewski return -EINVAL; 551e888d445SBartosz Golaszewski } 552e888d445SBartosz Golaszewski 553e888d445SBartosz Golaszewski cell = kzalloc(sizeof(*cell), GFP_KERNEL); 554e888d445SBartosz Golaszewski if (!cell) 555e888d445SBartosz Golaszewski return -ENOMEM; 556e888d445SBartosz Golaszewski 557e888d445SBartosz Golaszewski cell->nvmem = nvmem; 5580749aa25SSrinivas Kandagatla cell->np = of_node_get(child); 559e888d445SBartosz Golaszewski cell->offset = be32_to_cpup(addr++); 560e888d445SBartosz Golaszewski cell->bytes = be32_to_cpup(addr); 561badcdff1SRob Herring cell->name = kasprintf(GFP_KERNEL, "%pOFn", child); 562e888d445SBartosz Golaszewski 563e888d445SBartosz Golaszewski addr = of_get_property(child, "bits", &len); 564e888d445SBartosz Golaszewski if (addr && len == (2 * sizeof(u32))) { 565e888d445SBartosz Golaszewski cell->bit_offset = be32_to_cpup(addr++); 566e888d445SBartosz Golaszewski cell->nbits = be32_to_cpup(addr); 567e888d445SBartosz Golaszewski } 568e888d445SBartosz Golaszewski 569e888d445SBartosz Golaszewski if (cell->nbits) 570e888d445SBartosz Golaszewski cell->bytes = DIV_ROUND_UP( 571e888d445SBartosz Golaszewski cell->nbits + cell->bit_offset, 572e888d445SBartosz Golaszewski BITS_PER_BYTE); 573e888d445SBartosz Golaszewski 574e888d445SBartosz Golaszewski if (!IS_ALIGNED(cell->offset, nvmem->stride)) { 575e888d445SBartosz Golaszewski dev_err(dev, "cell %s unaligned to nvmem stride %d\n", 576e888d445SBartosz Golaszewski cell->name, nvmem->stride); 577e888d445SBartosz Golaszewski /* Cells already added will be freed later. */ 57816bb7abcSBitan Biswas kfree_const(cell->name); 579e888d445SBartosz Golaszewski kfree(cell); 580e888d445SBartosz Golaszewski return -EINVAL; 581e888d445SBartosz Golaszewski } 582e888d445SBartosz Golaszewski 583e888d445SBartosz Golaszewski nvmem_cell_add(cell); 584e888d445SBartosz Golaszewski } 585e888d445SBartosz Golaszewski 586e888d445SBartosz Golaszewski return 0; 587e888d445SBartosz Golaszewski } 588e888d445SBartosz Golaszewski 589eace75cfSSrinivas Kandagatla /** 590eace75cfSSrinivas Kandagatla * nvmem_register() - Register a nvmem device for given nvmem_config. 5913a758071SAndreas Färber * Also creates a binary entry in /sys/bus/nvmem/devices/dev-name/nvmem 592eace75cfSSrinivas Kandagatla * 593eace75cfSSrinivas Kandagatla * @config: nvmem device configuration with which nvmem device is created. 594eace75cfSSrinivas Kandagatla * 595eace75cfSSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device 596eace75cfSSrinivas Kandagatla * on success. 597eace75cfSSrinivas Kandagatla */ 598eace75cfSSrinivas Kandagatla 599eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem_register(const struct nvmem_config *config) 600eace75cfSSrinivas Kandagatla { 601eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem; 602eace75cfSSrinivas Kandagatla int rval; 603eace75cfSSrinivas Kandagatla 604eace75cfSSrinivas Kandagatla if (!config->dev) 605eace75cfSSrinivas Kandagatla return ERR_PTR(-EINVAL); 606eace75cfSSrinivas Kandagatla 607061a320bSSrinivas Kandagatla if (!config->reg_read && !config->reg_write) 608061a320bSSrinivas Kandagatla return ERR_PTR(-EINVAL); 609061a320bSSrinivas Kandagatla 610eace75cfSSrinivas Kandagatla nvmem = kzalloc(sizeof(*nvmem), GFP_KERNEL); 611eace75cfSSrinivas Kandagatla if (!nvmem) 612eace75cfSSrinivas Kandagatla return ERR_PTR(-ENOMEM); 613eace75cfSSrinivas Kandagatla 6141eb51d6aSBartosz Golaszewski rval = ida_alloc(&nvmem_ida, GFP_KERNEL); 615eace75cfSSrinivas Kandagatla if (rval < 0) { 616eace75cfSSrinivas Kandagatla kfree(nvmem); 617eace75cfSSrinivas Kandagatla return ERR_PTR(rval); 618eace75cfSSrinivas Kandagatla } 61931c6ff51SBartosz Golaszewski 6202a127da4SKhouloud Touil if (config->wp_gpio) 6212a127da4SKhouloud Touil nvmem->wp_gpio = config->wp_gpio; 6222a127da4SKhouloud Touil else 6232a127da4SKhouloud Touil nvmem->wp_gpio = gpiod_get_optional(config->dev, "wp", 6242a127da4SKhouloud Touil GPIOD_OUT_HIGH); 625f7d8d7dcSBartosz Golaszewski if (IS_ERR(nvmem->wp_gpio)) { 6261eb51d6aSBartosz Golaszewski ida_free(&nvmem_ida, nvmem->id); 627f7d8d7dcSBartosz Golaszewski rval = PTR_ERR(nvmem->wp_gpio); 628f7d8d7dcSBartosz Golaszewski kfree(nvmem); 629f7d8d7dcSBartosz Golaszewski return ERR_PTR(rval); 630f7d8d7dcSBartosz Golaszewski } 6312a127da4SKhouloud Touil 632c1de7f43SBartosz Golaszewski kref_init(&nvmem->refcnt); 633c7235ee3SBartosz Golaszewski INIT_LIST_HEAD(&nvmem->cells); 634c1de7f43SBartosz Golaszewski 635eace75cfSSrinivas Kandagatla nvmem->id = rval; 636eace75cfSSrinivas Kandagatla nvmem->owner = config->owner; 63717eb18d6SMasahiro Yamada if (!nvmem->owner && config->dev->driver) 63817eb18d6SMasahiro Yamada nvmem->owner = config->dev->driver->owner; 63999897efdSHeiner Kallweit nvmem->stride = config->stride ?: 1; 64099897efdSHeiner Kallweit nvmem->word_size = config->word_size ?: 1; 641795ddd18SSrinivas Kandagatla nvmem->size = config->size; 642eace75cfSSrinivas Kandagatla nvmem->dev.type = &nvmem_provider_type; 643eace75cfSSrinivas Kandagatla nvmem->dev.bus = &nvmem_bus_type; 644eace75cfSSrinivas Kandagatla nvmem->dev.parent = config->dev; 645e6de179dSSrinivas Kandagatla nvmem->root_only = config->root_only; 646795ddd18SSrinivas Kandagatla nvmem->priv = config->priv; 64716688453SAlexandre Belloni nvmem->type = config->type; 648795ddd18SSrinivas Kandagatla nvmem->reg_read = config->reg_read; 649795ddd18SSrinivas Kandagatla nvmem->reg_write = config->reg_write; 650517f14d9SBartosz Golaszewski if (!config->no_of_node) 651fc2f9970SHeiner Kallweit nvmem->dev.of_node = config->dev->of_node; 652fd0f4906SAndrey Smirnov 653731aa3faSSrinivas Kandagatla switch (config->id) { 654731aa3faSSrinivas Kandagatla case NVMEM_DEVID_NONE: 655fd0f4906SAndrey Smirnov dev_set_name(&nvmem->dev, "%s", config->name); 656731aa3faSSrinivas Kandagatla break; 657731aa3faSSrinivas Kandagatla case NVMEM_DEVID_AUTO: 658731aa3faSSrinivas Kandagatla dev_set_name(&nvmem->dev, "%s%d", config->name, nvmem->id); 659731aa3faSSrinivas Kandagatla break; 660731aa3faSSrinivas Kandagatla default: 661eace75cfSSrinivas Kandagatla dev_set_name(&nvmem->dev, "%s%d", 6625253193dSAban Bedel config->name ? : "nvmem", 6635253193dSAban Bedel config->name ? config->id : nvmem->id); 664731aa3faSSrinivas Kandagatla break; 665fd0f4906SAndrey Smirnov } 666eace75cfSSrinivas Kandagatla 6671716cfe8SAlban Bedel nvmem->read_only = device_property_present(config->dev, "read-only") || 6681716cfe8SAlban Bedel config->read_only || !nvmem->reg_write; 669eace75cfSSrinivas Kandagatla 67084400305SSrinivas Kandagatla #ifdef CONFIG_NVMEM_SYSFS 67184400305SSrinivas Kandagatla nvmem->dev.groups = nvmem_dev_groups; 67284400305SSrinivas Kandagatla #endif 673eace75cfSSrinivas Kandagatla 674eace75cfSSrinivas Kandagatla dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name); 675eace75cfSSrinivas Kandagatla 676f60442ddSSrinivas Kandagatla rval = device_register(&nvmem->dev); 677b6c217abSAndrew Lunn if (rval) 6783360acdfSJohan Hovold goto err_put_device; 679b6c217abSAndrew Lunn 680b6c217abSAndrew Lunn if (config->compat) { 681ae0c2d72SSrinivas Kandagatla rval = nvmem_sysfs_setup_compat(nvmem, config); 682b6c217abSAndrew Lunn if (rval) 6833360acdfSJohan Hovold goto err_device_del; 684eace75cfSSrinivas Kandagatla } 685eace75cfSSrinivas Kandagatla 686fa72d847SBartosz Golaszewski if (config->cells) { 687fa72d847SBartosz Golaszewski rval = nvmem_add_cells(nvmem, config->cells, config->ncells); 688fa72d847SBartosz Golaszewski if (rval) 689fa72d847SBartosz Golaszewski goto err_teardown_compat; 690fa72d847SBartosz Golaszewski } 691eace75cfSSrinivas Kandagatla 692b985f4cbSBartosz Golaszewski rval = nvmem_add_cells_from_table(nvmem); 693b985f4cbSBartosz Golaszewski if (rval) 694b985f4cbSBartosz Golaszewski goto err_remove_cells; 695b985f4cbSBartosz Golaszewski 696e888d445SBartosz Golaszewski rval = nvmem_add_cells_from_of(nvmem); 697e888d445SBartosz Golaszewski if (rval) 698e888d445SBartosz Golaszewski goto err_remove_cells; 699e888d445SBartosz Golaszewski 700f4853e1cSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_ADD, nvmem); 701bee1138bSBartosz Golaszewski 702eace75cfSSrinivas Kandagatla return nvmem; 7033360acdfSJohan Hovold 704b985f4cbSBartosz Golaszewski err_remove_cells: 705b985f4cbSBartosz Golaszewski nvmem_device_remove_all_cells(nvmem); 706fa72d847SBartosz Golaszewski err_teardown_compat: 707fa72d847SBartosz Golaszewski if (config->compat) 708ae0c2d72SSrinivas Kandagatla nvmem_sysfs_remove_compat(nvmem, config); 7093360acdfSJohan Hovold err_device_del: 7103360acdfSJohan Hovold device_del(&nvmem->dev); 7113360acdfSJohan Hovold err_put_device: 7123360acdfSJohan Hovold put_device(&nvmem->dev); 7133360acdfSJohan Hovold 714b6c217abSAndrew Lunn return ERR_PTR(rval); 715eace75cfSSrinivas Kandagatla } 716eace75cfSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_register); 717eace75cfSSrinivas Kandagatla 718c1de7f43SBartosz Golaszewski static void nvmem_device_release(struct kref *kref) 719c1de7f43SBartosz Golaszewski { 720c1de7f43SBartosz Golaszewski struct nvmem_device *nvmem; 721c1de7f43SBartosz Golaszewski 722c1de7f43SBartosz Golaszewski nvmem = container_of(kref, struct nvmem_device, refcnt); 723c1de7f43SBartosz Golaszewski 724bee1138bSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_REMOVE, nvmem); 725bee1138bSBartosz Golaszewski 726c1de7f43SBartosz Golaszewski if (nvmem->flags & FLAG_COMPAT) 727c1de7f43SBartosz Golaszewski device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); 728c1de7f43SBartosz Golaszewski 729c1de7f43SBartosz Golaszewski nvmem_device_remove_all_cells(nvmem); 730f60442ddSSrinivas Kandagatla device_unregister(&nvmem->dev); 731c1de7f43SBartosz Golaszewski } 732c1de7f43SBartosz Golaszewski 733eace75cfSSrinivas Kandagatla /** 734eace75cfSSrinivas Kandagatla * nvmem_unregister() - Unregister previously registered nvmem device 735eace75cfSSrinivas Kandagatla * 736eace75cfSSrinivas Kandagatla * @nvmem: Pointer to previously registered nvmem device. 737eace75cfSSrinivas Kandagatla */ 738bf58e882SBartosz Golaszewski void nvmem_unregister(struct nvmem_device *nvmem) 739eace75cfSSrinivas Kandagatla { 740c1de7f43SBartosz Golaszewski kref_put(&nvmem->refcnt, nvmem_device_release); 741eace75cfSSrinivas Kandagatla } 742eace75cfSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_unregister); 743eace75cfSSrinivas Kandagatla 744f1f50ecaSAndrey Smirnov static void devm_nvmem_release(struct device *dev, void *res) 745f1f50ecaSAndrey Smirnov { 746bf58e882SBartosz Golaszewski nvmem_unregister(*(struct nvmem_device **)res); 747f1f50ecaSAndrey Smirnov } 748f1f50ecaSAndrey Smirnov 749f1f50ecaSAndrey Smirnov /** 750f1f50ecaSAndrey Smirnov * devm_nvmem_register() - Register a managed nvmem device for given 751f1f50ecaSAndrey Smirnov * nvmem_config. 7523a758071SAndreas Färber * Also creates a binary entry in /sys/bus/nvmem/devices/dev-name/nvmem 753f1f50ecaSAndrey Smirnov * 754b378c779SSrinivas Kandagatla * @dev: Device that uses the nvmem device. 755f1f50ecaSAndrey Smirnov * @config: nvmem device configuration with which nvmem device is created. 756f1f50ecaSAndrey Smirnov * 757f1f50ecaSAndrey Smirnov * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device 758f1f50ecaSAndrey Smirnov * on success. 759f1f50ecaSAndrey Smirnov */ 760f1f50ecaSAndrey Smirnov struct nvmem_device *devm_nvmem_register(struct device *dev, 761f1f50ecaSAndrey Smirnov const struct nvmem_config *config) 762f1f50ecaSAndrey Smirnov { 763f1f50ecaSAndrey Smirnov struct nvmem_device **ptr, *nvmem; 764f1f50ecaSAndrey Smirnov 765f1f50ecaSAndrey Smirnov ptr = devres_alloc(devm_nvmem_release, sizeof(*ptr), GFP_KERNEL); 766f1f50ecaSAndrey Smirnov if (!ptr) 767f1f50ecaSAndrey Smirnov return ERR_PTR(-ENOMEM); 768f1f50ecaSAndrey Smirnov 769f1f50ecaSAndrey Smirnov nvmem = nvmem_register(config); 770f1f50ecaSAndrey Smirnov 771f1f50ecaSAndrey Smirnov if (!IS_ERR(nvmem)) { 772f1f50ecaSAndrey Smirnov *ptr = nvmem; 773f1f50ecaSAndrey Smirnov devres_add(dev, ptr); 774f1f50ecaSAndrey Smirnov } else { 775f1f50ecaSAndrey Smirnov devres_free(ptr); 776f1f50ecaSAndrey Smirnov } 777f1f50ecaSAndrey Smirnov 778f1f50ecaSAndrey Smirnov return nvmem; 779f1f50ecaSAndrey Smirnov } 780f1f50ecaSAndrey Smirnov EXPORT_SYMBOL_GPL(devm_nvmem_register); 781f1f50ecaSAndrey Smirnov 782f1f50ecaSAndrey Smirnov static int devm_nvmem_match(struct device *dev, void *res, void *data) 783f1f50ecaSAndrey Smirnov { 784f1f50ecaSAndrey Smirnov struct nvmem_device **r = res; 785f1f50ecaSAndrey Smirnov 786f1f50ecaSAndrey Smirnov return *r == data; 787f1f50ecaSAndrey Smirnov } 788f1f50ecaSAndrey Smirnov 789f1f50ecaSAndrey Smirnov /** 790f1f50ecaSAndrey Smirnov * devm_nvmem_unregister() - Unregister previously registered managed nvmem 791f1f50ecaSAndrey Smirnov * device. 792f1f50ecaSAndrey Smirnov * 793b378c779SSrinivas Kandagatla * @dev: Device that uses the nvmem device. 794f1f50ecaSAndrey Smirnov * @nvmem: Pointer to previously registered nvmem device. 795f1f50ecaSAndrey Smirnov * 7963a758071SAndreas Färber * Return: Will be negative on error or zero on success. 797f1f50ecaSAndrey Smirnov */ 798f1f50ecaSAndrey Smirnov int devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem) 799f1f50ecaSAndrey Smirnov { 800f1f50ecaSAndrey Smirnov return devres_release(dev, devm_nvmem_release, devm_nvmem_match, nvmem); 801f1f50ecaSAndrey Smirnov } 802f1f50ecaSAndrey Smirnov EXPORT_SYMBOL(devm_nvmem_unregister); 803f1f50ecaSAndrey Smirnov 8048c2a2b8cSThomas Bogendoerfer static struct nvmem_device *__nvmem_device_get(void *data, 8058c2a2b8cSThomas Bogendoerfer int (*match)(struct device *dev, const void *data)) 80669aba794SSrinivas Kandagatla { 80769aba794SSrinivas Kandagatla struct nvmem_device *nvmem = NULL; 8088c2a2b8cSThomas Bogendoerfer struct device *dev; 80969aba794SSrinivas Kandagatla 810c7235ee3SBartosz Golaszewski mutex_lock(&nvmem_mutex); 8118c2a2b8cSThomas Bogendoerfer dev = bus_find_device(&nvmem_bus_type, NULL, data, match); 8128c2a2b8cSThomas Bogendoerfer if (dev) 8138c2a2b8cSThomas Bogendoerfer nvmem = to_nvmem_device(dev); 81469aba794SSrinivas Kandagatla mutex_unlock(&nvmem_mutex); 815c7235ee3SBartosz Golaszewski if (!nvmem) 816c7235ee3SBartosz Golaszewski return ERR_PTR(-EPROBE_DEFER); 81769aba794SSrinivas Kandagatla 81869aba794SSrinivas Kandagatla if (!try_module_get(nvmem->owner)) { 81969aba794SSrinivas Kandagatla dev_err(&nvmem->dev, 82069aba794SSrinivas Kandagatla "could not increase module refcount for cell %s\n", 8215db652c9SBartosz Golaszewski nvmem_dev_name(nvmem)); 82269aba794SSrinivas Kandagatla 82373e9dc4dSAlban Bedel put_device(&nvmem->dev); 82469aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 82569aba794SSrinivas Kandagatla } 82669aba794SSrinivas Kandagatla 827c1de7f43SBartosz Golaszewski kref_get(&nvmem->refcnt); 828c1de7f43SBartosz Golaszewski 82969aba794SSrinivas Kandagatla return nvmem; 83069aba794SSrinivas Kandagatla } 83169aba794SSrinivas Kandagatla 83269aba794SSrinivas Kandagatla static void __nvmem_device_put(struct nvmem_device *nvmem) 83369aba794SSrinivas Kandagatla { 83473e9dc4dSAlban Bedel put_device(&nvmem->dev); 83569aba794SSrinivas Kandagatla module_put(nvmem->owner); 836c1de7f43SBartosz Golaszewski kref_put(&nvmem->refcnt, nvmem_device_release); 83769aba794SSrinivas Kandagatla } 83869aba794SSrinivas Kandagatla 839e701c67cSMasahiro Yamada #if IS_ENABLED(CONFIG_OF) 840e2a5402eSSrinivas Kandagatla /** 841e2a5402eSSrinivas Kandagatla * of_nvmem_device_get() - Get nvmem device from a given id 842e2a5402eSSrinivas Kandagatla * 84329143268SVivek Gautam * @np: Device tree node that uses the nvmem device. 844e2a5402eSSrinivas Kandagatla * @id: nvmem name from nvmem-names property. 845e2a5402eSSrinivas Kandagatla * 846e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device 847e2a5402eSSrinivas Kandagatla * on success. 848e2a5402eSSrinivas Kandagatla */ 849e2a5402eSSrinivas Kandagatla struct nvmem_device *of_nvmem_device_get(struct device_node *np, const char *id) 850e2a5402eSSrinivas Kandagatla { 851e2a5402eSSrinivas Kandagatla 852e2a5402eSSrinivas Kandagatla struct device_node *nvmem_np; 853b1c194dcSVadym Kochan struct nvmem_device *nvmem; 854d4e7fef1SAlban Bedel int index = 0; 855e2a5402eSSrinivas Kandagatla 856d4e7fef1SAlban Bedel if (id) 857e2a5402eSSrinivas Kandagatla index = of_property_match_string(np, "nvmem-names", id); 858e2a5402eSSrinivas Kandagatla 859e2a5402eSSrinivas Kandagatla nvmem_np = of_parse_phandle(np, "nvmem", index); 860e2a5402eSSrinivas Kandagatla if (!nvmem_np) 861d4e7fef1SAlban Bedel return ERR_PTR(-ENOENT); 862e2a5402eSSrinivas Kandagatla 863b1c194dcSVadym Kochan nvmem = __nvmem_device_get(nvmem_np, device_match_of_node); 864b1c194dcSVadym Kochan of_node_put(nvmem_np); 865b1c194dcSVadym Kochan return nvmem; 866e2a5402eSSrinivas Kandagatla } 867e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_nvmem_device_get); 868e2a5402eSSrinivas Kandagatla #endif 869e2a5402eSSrinivas Kandagatla 870e2a5402eSSrinivas Kandagatla /** 871e2a5402eSSrinivas Kandagatla * nvmem_device_get() - Get nvmem device from a given id 872e2a5402eSSrinivas Kandagatla * 87329143268SVivek Gautam * @dev: Device that uses the nvmem device. 87429143268SVivek Gautam * @dev_name: name of the requested nvmem device. 875e2a5402eSSrinivas Kandagatla * 876e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device 877e2a5402eSSrinivas Kandagatla * on success. 878e2a5402eSSrinivas Kandagatla */ 879e2a5402eSSrinivas Kandagatla struct nvmem_device *nvmem_device_get(struct device *dev, const char *dev_name) 880e2a5402eSSrinivas Kandagatla { 881e2a5402eSSrinivas Kandagatla if (dev->of_node) { /* try dt first */ 882e2a5402eSSrinivas Kandagatla struct nvmem_device *nvmem; 883e2a5402eSSrinivas Kandagatla 884e2a5402eSSrinivas Kandagatla nvmem = of_nvmem_device_get(dev->of_node, dev_name); 885e2a5402eSSrinivas Kandagatla 886e2a5402eSSrinivas Kandagatla if (!IS_ERR(nvmem) || PTR_ERR(nvmem) == -EPROBE_DEFER) 887e2a5402eSSrinivas Kandagatla return nvmem; 888e2a5402eSSrinivas Kandagatla 889e2a5402eSSrinivas Kandagatla } 890e2a5402eSSrinivas Kandagatla 8918c2a2b8cSThomas Bogendoerfer return __nvmem_device_get((void *)dev_name, device_match_name); 892e2a5402eSSrinivas Kandagatla } 893e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_get); 894e2a5402eSSrinivas Kandagatla 8958c2a2b8cSThomas Bogendoerfer /** 8968c2a2b8cSThomas Bogendoerfer * nvmem_device_find() - Find nvmem device with matching function 8978c2a2b8cSThomas Bogendoerfer * 8988c2a2b8cSThomas Bogendoerfer * @data: Data to pass to match function 8998c2a2b8cSThomas Bogendoerfer * @match: Callback function to check device 9008c2a2b8cSThomas Bogendoerfer * 9018c2a2b8cSThomas Bogendoerfer * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device 9028c2a2b8cSThomas Bogendoerfer * on success. 9038c2a2b8cSThomas Bogendoerfer */ 9048c2a2b8cSThomas Bogendoerfer struct nvmem_device *nvmem_device_find(void *data, 9058c2a2b8cSThomas Bogendoerfer int (*match)(struct device *dev, const void *data)) 9068c2a2b8cSThomas Bogendoerfer { 9078c2a2b8cSThomas Bogendoerfer return __nvmem_device_get(data, match); 9088c2a2b8cSThomas Bogendoerfer } 9098c2a2b8cSThomas Bogendoerfer EXPORT_SYMBOL_GPL(nvmem_device_find); 9108c2a2b8cSThomas Bogendoerfer 911e2a5402eSSrinivas Kandagatla static int devm_nvmem_device_match(struct device *dev, void *res, void *data) 912e2a5402eSSrinivas Kandagatla { 913e2a5402eSSrinivas Kandagatla struct nvmem_device **nvmem = res; 914e2a5402eSSrinivas Kandagatla 915e2a5402eSSrinivas Kandagatla if (WARN_ON(!nvmem || !*nvmem)) 916e2a5402eSSrinivas Kandagatla return 0; 917e2a5402eSSrinivas Kandagatla 918e2a5402eSSrinivas Kandagatla return *nvmem == data; 919e2a5402eSSrinivas Kandagatla } 920e2a5402eSSrinivas Kandagatla 921e2a5402eSSrinivas Kandagatla static void devm_nvmem_device_release(struct device *dev, void *res) 922e2a5402eSSrinivas Kandagatla { 923e2a5402eSSrinivas Kandagatla nvmem_device_put(*(struct nvmem_device **)res); 924e2a5402eSSrinivas Kandagatla } 925e2a5402eSSrinivas Kandagatla 926e2a5402eSSrinivas Kandagatla /** 927e2a5402eSSrinivas Kandagatla * devm_nvmem_device_put() - put alredy got nvmem device 928e2a5402eSSrinivas Kandagatla * 92929143268SVivek Gautam * @dev: Device that uses the nvmem device. 930e2a5402eSSrinivas Kandagatla * @nvmem: pointer to nvmem device allocated by devm_nvmem_cell_get(), 931e2a5402eSSrinivas Kandagatla * that needs to be released. 932e2a5402eSSrinivas Kandagatla */ 933e2a5402eSSrinivas Kandagatla void devm_nvmem_device_put(struct device *dev, struct nvmem_device *nvmem) 934e2a5402eSSrinivas Kandagatla { 935e2a5402eSSrinivas Kandagatla int ret; 936e2a5402eSSrinivas Kandagatla 937e2a5402eSSrinivas Kandagatla ret = devres_release(dev, devm_nvmem_device_release, 938e2a5402eSSrinivas Kandagatla devm_nvmem_device_match, nvmem); 939e2a5402eSSrinivas Kandagatla 940e2a5402eSSrinivas Kandagatla WARN_ON(ret); 941e2a5402eSSrinivas Kandagatla } 942e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_device_put); 943e2a5402eSSrinivas Kandagatla 944e2a5402eSSrinivas Kandagatla /** 945e2a5402eSSrinivas Kandagatla * nvmem_device_put() - put alredy got nvmem device 946e2a5402eSSrinivas Kandagatla * 947e2a5402eSSrinivas Kandagatla * @nvmem: pointer to nvmem device that needs to be released. 948e2a5402eSSrinivas Kandagatla */ 949e2a5402eSSrinivas Kandagatla void nvmem_device_put(struct nvmem_device *nvmem) 950e2a5402eSSrinivas Kandagatla { 951e2a5402eSSrinivas Kandagatla __nvmem_device_put(nvmem); 952e2a5402eSSrinivas Kandagatla } 953e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_put); 954e2a5402eSSrinivas Kandagatla 955e2a5402eSSrinivas Kandagatla /** 956e2a5402eSSrinivas Kandagatla * devm_nvmem_device_get() - Get nvmem cell of device form a given id 957e2a5402eSSrinivas Kandagatla * 95829143268SVivek Gautam * @dev: Device that requests the nvmem device. 95929143268SVivek Gautam * @id: name id for the requested nvmem device. 960e2a5402eSSrinivas Kandagatla * 961e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_cell 962e2a5402eSSrinivas Kandagatla * on success. The nvmem_cell will be freed by the automatically once the 963e2a5402eSSrinivas Kandagatla * device is freed. 964e2a5402eSSrinivas Kandagatla */ 965e2a5402eSSrinivas Kandagatla struct nvmem_device *devm_nvmem_device_get(struct device *dev, const char *id) 966e2a5402eSSrinivas Kandagatla { 967e2a5402eSSrinivas Kandagatla struct nvmem_device **ptr, *nvmem; 968e2a5402eSSrinivas Kandagatla 969e2a5402eSSrinivas Kandagatla ptr = devres_alloc(devm_nvmem_device_release, sizeof(*ptr), GFP_KERNEL); 970e2a5402eSSrinivas Kandagatla if (!ptr) 971e2a5402eSSrinivas Kandagatla return ERR_PTR(-ENOMEM); 972e2a5402eSSrinivas Kandagatla 973e2a5402eSSrinivas Kandagatla nvmem = nvmem_device_get(dev, id); 974e2a5402eSSrinivas Kandagatla if (!IS_ERR(nvmem)) { 975e2a5402eSSrinivas Kandagatla *ptr = nvmem; 976e2a5402eSSrinivas Kandagatla devres_add(dev, ptr); 977e2a5402eSSrinivas Kandagatla } else { 978e2a5402eSSrinivas Kandagatla devres_free(ptr); 979e2a5402eSSrinivas Kandagatla } 980e2a5402eSSrinivas Kandagatla 981e2a5402eSSrinivas Kandagatla return nvmem; 982e2a5402eSSrinivas Kandagatla } 983e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_device_get); 984e2a5402eSSrinivas Kandagatla 985506157beSBartosz Golaszewski static struct nvmem_cell * 986506157beSBartosz Golaszewski nvmem_cell_get_from_lookup(struct device *dev, const char *con_id) 98769aba794SSrinivas Kandagatla { 988506157beSBartosz Golaszewski struct nvmem_cell *cell = ERR_PTR(-ENOENT); 989506157beSBartosz Golaszewski struct nvmem_cell_lookup *lookup; 99069aba794SSrinivas Kandagatla struct nvmem_device *nvmem; 991506157beSBartosz Golaszewski const char *dev_id; 99269aba794SSrinivas Kandagatla 993506157beSBartosz Golaszewski if (!dev) 994506157beSBartosz Golaszewski return ERR_PTR(-EINVAL); 99569aba794SSrinivas Kandagatla 996506157beSBartosz Golaszewski dev_id = dev_name(dev); 997506157beSBartosz Golaszewski 998506157beSBartosz Golaszewski mutex_lock(&nvmem_lookup_mutex); 999506157beSBartosz Golaszewski 1000506157beSBartosz Golaszewski list_for_each_entry(lookup, &nvmem_lookup_list, node) { 1001506157beSBartosz Golaszewski if ((strcmp(lookup->dev_id, dev_id) == 0) && 1002506157beSBartosz Golaszewski (strcmp(lookup->con_id, con_id) == 0)) { 1003506157beSBartosz Golaszewski /* This is the right entry. */ 10048c2a2b8cSThomas Bogendoerfer nvmem = __nvmem_device_get((void *)lookup->nvmem_name, 10058c2a2b8cSThomas Bogendoerfer device_match_name); 1006cccb3b19SBartosz Golaszewski if (IS_ERR(nvmem)) { 1007506157beSBartosz Golaszewski /* Provider may not be registered yet. */ 1008cccb3b19SBartosz Golaszewski cell = ERR_CAST(nvmem); 10099bfd8198SAlban Bedel break; 1010506157beSBartosz Golaszewski } 1011506157beSBartosz Golaszewski 1012506157beSBartosz Golaszewski cell = nvmem_find_cell_by_name(nvmem, 1013506157beSBartosz Golaszewski lookup->cell_name); 1014506157beSBartosz Golaszewski if (!cell) { 1015506157beSBartosz Golaszewski __nvmem_device_put(nvmem); 1016cccb3b19SBartosz Golaszewski cell = ERR_PTR(-ENOENT); 1017506157beSBartosz Golaszewski } 10189bfd8198SAlban Bedel break; 1019506157beSBartosz Golaszewski } 1020506157beSBartosz Golaszewski } 1021506157beSBartosz Golaszewski 1022506157beSBartosz Golaszewski mutex_unlock(&nvmem_lookup_mutex); 102369aba794SSrinivas Kandagatla return cell; 102469aba794SSrinivas Kandagatla } 102569aba794SSrinivas Kandagatla 1026e701c67cSMasahiro Yamada #if IS_ENABLED(CONFIG_OF) 10273c53e235SArnd Bergmann static struct nvmem_cell * 10280749aa25SSrinivas Kandagatla nvmem_find_cell_by_node(struct nvmem_device *nvmem, struct device_node *np) 10293c53e235SArnd Bergmann { 10301c832674SAlban Bedel struct nvmem_cell *iter, *cell = NULL; 10313c53e235SArnd Bergmann 10323c53e235SArnd Bergmann mutex_lock(&nvmem_mutex); 10331c832674SAlban Bedel list_for_each_entry(iter, &nvmem->cells, node) { 10341c832674SAlban Bedel if (np == iter->np) { 10351c832674SAlban Bedel cell = iter; 10363c53e235SArnd Bergmann break; 10373c53e235SArnd Bergmann } 10381c832674SAlban Bedel } 10393c53e235SArnd Bergmann mutex_unlock(&nvmem_mutex); 10403c53e235SArnd Bergmann 10413c53e235SArnd Bergmann return cell; 10423c53e235SArnd Bergmann } 10433c53e235SArnd Bergmann 104469aba794SSrinivas Kandagatla /** 104569aba794SSrinivas Kandagatla * of_nvmem_cell_get() - Get a nvmem cell from given device node and cell id 104669aba794SSrinivas Kandagatla * 104729143268SVivek Gautam * @np: Device tree node that uses the nvmem cell. 1048165589f0SBartosz Golaszewski * @id: nvmem cell name from nvmem-cell-names property, or NULL 1049fd0c478cSVivek Gautam * for the cell at index 0 (the lone cell with no accompanying 1050fd0c478cSVivek Gautam * nvmem-cell-names property). 105169aba794SSrinivas Kandagatla * 105269aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 105369aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 105469aba794SSrinivas Kandagatla * nvmem_cell_put(). 105569aba794SSrinivas Kandagatla */ 1056165589f0SBartosz Golaszewski struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *id) 105769aba794SSrinivas Kandagatla { 105869aba794SSrinivas Kandagatla struct device_node *cell_np, *nvmem_np; 105969aba794SSrinivas Kandagatla struct nvmem_device *nvmem; 1060e888d445SBartosz Golaszewski struct nvmem_cell *cell; 1061fd0c478cSVivek Gautam int index = 0; 106269aba794SSrinivas Kandagatla 1063fd0c478cSVivek Gautam /* if cell name exists, find index to the name */ 1064165589f0SBartosz Golaszewski if (id) 1065165589f0SBartosz Golaszewski index = of_property_match_string(np, "nvmem-cell-names", id); 106669aba794SSrinivas Kandagatla 106769aba794SSrinivas Kandagatla cell_np = of_parse_phandle(np, "nvmem-cells", index); 106869aba794SSrinivas Kandagatla if (!cell_np) 10695087cc19SAlban Bedel return ERR_PTR(-ENOENT); 107069aba794SSrinivas Kandagatla 107169aba794SSrinivas Kandagatla nvmem_np = of_get_next_parent(cell_np); 107269aba794SSrinivas Kandagatla if (!nvmem_np) 107369aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 107469aba794SSrinivas Kandagatla 10758c2a2b8cSThomas Bogendoerfer nvmem = __nvmem_device_get(nvmem_np, device_match_of_node); 1076aad8d097SMasahiro Yamada of_node_put(nvmem_np); 107769aba794SSrinivas Kandagatla if (IS_ERR(nvmem)) 107869aba794SSrinivas Kandagatla return ERR_CAST(nvmem); 107969aba794SSrinivas Kandagatla 10800749aa25SSrinivas Kandagatla cell = nvmem_find_cell_by_node(nvmem, cell_np); 108169aba794SSrinivas Kandagatla if (!cell) { 1082e888d445SBartosz Golaszewski __nvmem_device_put(nvmem); 1083e888d445SBartosz Golaszewski return ERR_PTR(-ENOENT); 108469aba794SSrinivas Kandagatla } 108569aba794SSrinivas Kandagatla 108669aba794SSrinivas Kandagatla return cell; 108769aba794SSrinivas Kandagatla } 108869aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_nvmem_cell_get); 108969aba794SSrinivas Kandagatla #endif 109069aba794SSrinivas Kandagatla 109169aba794SSrinivas Kandagatla /** 109269aba794SSrinivas Kandagatla * nvmem_cell_get() - Get nvmem cell of device form a given cell name 109369aba794SSrinivas Kandagatla * 109429143268SVivek Gautam * @dev: Device that requests the nvmem cell. 1095165589f0SBartosz Golaszewski * @id: nvmem cell name to get (this corresponds with the name from the 1096165589f0SBartosz Golaszewski * nvmem-cell-names property for DT systems and with the con_id from 1097165589f0SBartosz Golaszewski * the lookup entry for non-DT systems). 109869aba794SSrinivas Kandagatla * 109969aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 110069aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 110169aba794SSrinivas Kandagatla * nvmem_cell_put(). 110269aba794SSrinivas Kandagatla */ 1103165589f0SBartosz Golaszewski struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *id) 110469aba794SSrinivas Kandagatla { 110569aba794SSrinivas Kandagatla struct nvmem_cell *cell; 110669aba794SSrinivas Kandagatla 110769aba794SSrinivas Kandagatla if (dev->of_node) { /* try dt first */ 1108165589f0SBartosz Golaszewski cell = of_nvmem_cell_get(dev->of_node, id); 110969aba794SSrinivas Kandagatla if (!IS_ERR(cell) || PTR_ERR(cell) == -EPROBE_DEFER) 111069aba794SSrinivas Kandagatla return cell; 111169aba794SSrinivas Kandagatla } 111269aba794SSrinivas Kandagatla 1113165589f0SBartosz Golaszewski /* NULL cell id only allowed for device tree; invalid otherwise */ 1114165589f0SBartosz Golaszewski if (!id) 111587ed1405SDouglas Anderson return ERR_PTR(-EINVAL); 111687ed1405SDouglas Anderson 1117165589f0SBartosz Golaszewski return nvmem_cell_get_from_lookup(dev, id); 111869aba794SSrinivas Kandagatla } 111969aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_get); 112069aba794SSrinivas Kandagatla 112169aba794SSrinivas Kandagatla static void devm_nvmem_cell_release(struct device *dev, void *res) 112269aba794SSrinivas Kandagatla { 112369aba794SSrinivas Kandagatla nvmem_cell_put(*(struct nvmem_cell **)res); 112469aba794SSrinivas Kandagatla } 112569aba794SSrinivas Kandagatla 112669aba794SSrinivas Kandagatla /** 112769aba794SSrinivas Kandagatla * devm_nvmem_cell_get() - Get nvmem cell of device form a given id 112869aba794SSrinivas Kandagatla * 112929143268SVivek Gautam * @dev: Device that requests the nvmem cell. 113029143268SVivek Gautam * @id: nvmem cell name id to get. 113169aba794SSrinivas Kandagatla * 113269aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 113369aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 113469aba794SSrinivas Kandagatla * automatically once the device is freed. 113569aba794SSrinivas Kandagatla */ 113669aba794SSrinivas Kandagatla struct nvmem_cell *devm_nvmem_cell_get(struct device *dev, const char *id) 113769aba794SSrinivas Kandagatla { 113869aba794SSrinivas Kandagatla struct nvmem_cell **ptr, *cell; 113969aba794SSrinivas Kandagatla 114069aba794SSrinivas Kandagatla ptr = devres_alloc(devm_nvmem_cell_release, sizeof(*ptr), GFP_KERNEL); 114169aba794SSrinivas Kandagatla if (!ptr) 114269aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 114369aba794SSrinivas Kandagatla 114469aba794SSrinivas Kandagatla cell = nvmem_cell_get(dev, id); 114569aba794SSrinivas Kandagatla if (!IS_ERR(cell)) { 114669aba794SSrinivas Kandagatla *ptr = cell; 114769aba794SSrinivas Kandagatla devres_add(dev, ptr); 114869aba794SSrinivas Kandagatla } else { 114969aba794SSrinivas Kandagatla devres_free(ptr); 115069aba794SSrinivas Kandagatla } 115169aba794SSrinivas Kandagatla 115269aba794SSrinivas Kandagatla return cell; 115369aba794SSrinivas Kandagatla } 115469aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_cell_get); 115569aba794SSrinivas Kandagatla 115669aba794SSrinivas Kandagatla static int devm_nvmem_cell_match(struct device *dev, void *res, void *data) 115769aba794SSrinivas Kandagatla { 115869aba794SSrinivas Kandagatla struct nvmem_cell **c = res; 115969aba794SSrinivas Kandagatla 116069aba794SSrinivas Kandagatla if (WARN_ON(!c || !*c)) 116169aba794SSrinivas Kandagatla return 0; 116269aba794SSrinivas Kandagatla 116369aba794SSrinivas Kandagatla return *c == data; 116469aba794SSrinivas Kandagatla } 116569aba794SSrinivas Kandagatla 116669aba794SSrinivas Kandagatla /** 116769aba794SSrinivas Kandagatla * devm_nvmem_cell_put() - Release previously allocated nvmem cell 116869aba794SSrinivas Kandagatla * from devm_nvmem_cell_get. 116969aba794SSrinivas Kandagatla * 117029143268SVivek Gautam * @dev: Device that requests the nvmem cell. 117129143268SVivek Gautam * @cell: Previously allocated nvmem cell by devm_nvmem_cell_get(). 117269aba794SSrinivas Kandagatla */ 117369aba794SSrinivas Kandagatla void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell) 117469aba794SSrinivas Kandagatla { 117569aba794SSrinivas Kandagatla int ret; 117669aba794SSrinivas Kandagatla 117769aba794SSrinivas Kandagatla ret = devres_release(dev, devm_nvmem_cell_release, 117869aba794SSrinivas Kandagatla devm_nvmem_cell_match, cell); 117969aba794SSrinivas Kandagatla 118069aba794SSrinivas Kandagatla WARN_ON(ret); 118169aba794SSrinivas Kandagatla } 118269aba794SSrinivas Kandagatla EXPORT_SYMBOL(devm_nvmem_cell_put); 118369aba794SSrinivas Kandagatla 118469aba794SSrinivas Kandagatla /** 118569aba794SSrinivas Kandagatla * nvmem_cell_put() - Release previously allocated nvmem cell. 118669aba794SSrinivas Kandagatla * 118729143268SVivek Gautam * @cell: Previously allocated nvmem cell by nvmem_cell_get(). 118869aba794SSrinivas Kandagatla */ 118969aba794SSrinivas Kandagatla void nvmem_cell_put(struct nvmem_cell *cell) 119069aba794SSrinivas Kandagatla { 119169aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 119269aba794SSrinivas Kandagatla 119369aba794SSrinivas Kandagatla __nvmem_device_put(nvmem); 119469aba794SSrinivas Kandagatla } 119569aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_put); 119669aba794SSrinivas Kandagatla 1197f7c04f16SMasahiro Yamada static void nvmem_shift_read_buffer_in_place(struct nvmem_cell *cell, void *buf) 119869aba794SSrinivas Kandagatla { 119969aba794SSrinivas Kandagatla u8 *p, *b; 12002fe518feSJorge Ramirez-Ortiz int i, extra, bit_offset = cell->bit_offset; 120169aba794SSrinivas Kandagatla 120269aba794SSrinivas Kandagatla p = b = buf; 120369aba794SSrinivas Kandagatla if (bit_offset) { 120469aba794SSrinivas Kandagatla /* First shift */ 120569aba794SSrinivas Kandagatla *b++ >>= bit_offset; 120669aba794SSrinivas Kandagatla 120769aba794SSrinivas Kandagatla /* setup rest of the bytes if any */ 120869aba794SSrinivas Kandagatla for (i = 1; i < cell->bytes; i++) { 120969aba794SSrinivas Kandagatla /* Get bits from next byte and shift them towards msb */ 121069aba794SSrinivas Kandagatla *p |= *b << (BITS_PER_BYTE - bit_offset); 121169aba794SSrinivas Kandagatla 121269aba794SSrinivas Kandagatla p = b; 121369aba794SSrinivas Kandagatla *b++ >>= bit_offset; 121469aba794SSrinivas Kandagatla } 12152fe518feSJorge Ramirez-Ortiz } else { 12162fe518feSJorge Ramirez-Ortiz /* point to the msb */ 12172fe518feSJorge Ramirez-Ortiz p += cell->bytes - 1; 12182fe518feSJorge Ramirez-Ortiz } 121969aba794SSrinivas Kandagatla 122069aba794SSrinivas Kandagatla /* result fits in less bytes */ 12212fe518feSJorge Ramirez-Ortiz extra = cell->bytes - DIV_ROUND_UP(cell->nbits, BITS_PER_BYTE); 12222fe518feSJorge Ramirez-Ortiz while (--extra >= 0) 122369aba794SSrinivas Kandagatla *p-- = 0; 12242fe518feSJorge Ramirez-Ortiz 122569aba794SSrinivas Kandagatla /* clear msb bits if any leftover in the last byte */ 122669aba794SSrinivas Kandagatla *p &= GENMASK((cell->nbits%BITS_PER_BYTE) - 1, 0); 122769aba794SSrinivas Kandagatla } 122869aba794SSrinivas Kandagatla 122969aba794SSrinivas Kandagatla static int __nvmem_cell_read(struct nvmem_device *nvmem, 123069aba794SSrinivas Kandagatla struct nvmem_cell *cell, 123169aba794SSrinivas Kandagatla void *buf, size_t *len) 123269aba794SSrinivas Kandagatla { 123369aba794SSrinivas Kandagatla int rc; 123469aba794SSrinivas Kandagatla 1235795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, cell->offset, buf, cell->bytes); 123669aba794SSrinivas Kandagatla 1237287980e4SArnd Bergmann if (rc) 123869aba794SSrinivas Kandagatla return rc; 123969aba794SSrinivas Kandagatla 124069aba794SSrinivas Kandagatla /* shift bits in-place */ 1241cbf854abSAxel Lin if (cell->bit_offset || cell->nbits) 124269aba794SSrinivas Kandagatla nvmem_shift_read_buffer_in_place(cell, buf); 124369aba794SSrinivas Kandagatla 12443b4a6877SVivek Gautam if (len) 124569aba794SSrinivas Kandagatla *len = cell->bytes; 124669aba794SSrinivas Kandagatla 124769aba794SSrinivas Kandagatla return 0; 124869aba794SSrinivas Kandagatla } 124969aba794SSrinivas Kandagatla 125069aba794SSrinivas Kandagatla /** 125169aba794SSrinivas Kandagatla * nvmem_cell_read() - Read a given nvmem cell 125269aba794SSrinivas Kandagatla * 125369aba794SSrinivas Kandagatla * @cell: nvmem cell to be read. 12543b4a6877SVivek Gautam * @len: pointer to length of cell which will be populated on successful read; 12553b4a6877SVivek Gautam * can be NULL. 125669aba794SSrinivas Kandagatla * 1257b577fafcSBrian Norris * Return: ERR_PTR() on error or a valid pointer to a buffer on success. The 1258b577fafcSBrian Norris * buffer should be freed by the consumer with a kfree(). 125969aba794SSrinivas Kandagatla */ 126069aba794SSrinivas Kandagatla void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len) 126169aba794SSrinivas Kandagatla { 126269aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 126369aba794SSrinivas Kandagatla u8 *buf; 126469aba794SSrinivas Kandagatla int rc; 126569aba794SSrinivas Kandagatla 1266795ddd18SSrinivas Kandagatla if (!nvmem) 126769aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 126869aba794SSrinivas Kandagatla 126969aba794SSrinivas Kandagatla buf = kzalloc(cell->bytes, GFP_KERNEL); 127069aba794SSrinivas Kandagatla if (!buf) 127169aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 127269aba794SSrinivas Kandagatla 127369aba794SSrinivas Kandagatla rc = __nvmem_cell_read(nvmem, cell, buf, len); 1274287980e4SArnd Bergmann if (rc) { 127569aba794SSrinivas Kandagatla kfree(buf); 127669aba794SSrinivas Kandagatla return ERR_PTR(rc); 127769aba794SSrinivas Kandagatla } 127869aba794SSrinivas Kandagatla 127969aba794SSrinivas Kandagatla return buf; 128069aba794SSrinivas Kandagatla } 128169aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_read); 128269aba794SSrinivas Kandagatla 1283f7c04f16SMasahiro Yamada static void *nvmem_cell_prepare_write_buffer(struct nvmem_cell *cell, 128469aba794SSrinivas Kandagatla u8 *_buf, int len) 128569aba794SSrinivas Kandagatla { 128669aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 128769aba794SSrinivas Kandagatla int i, rc, nbits, bit_offset = cell->bit_offset; 128869aba794SSrinivas Kandagatla u8 v, *p, *buf, *b, pbyte, pbits; 128969aba794SSrinivas Kandagatla 129069aba794SSrinivas Kandagatla nbits = cell->nbits; 129169aba794SSrinivas Kandagatla buf = kzalloc(cell->bytes, GFP_KERNEL); 129269aba794SSrinivas Kandagatla if (!buf) 129369aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 129469aba794SSrinivas Kandagatla 129569aba794SSrinivas Kandagatla memcpy(buf, _buf, len); 129669aba794SSrinivas Kandagatla p = b = buf; 129769aba794SSrinivas Kandagatla 129869aba794SSrinivas Kandagatla if (bit_offset) { 129969aba794SSrinivas Kandagatla pbyte = *b; 130069aba794SSrinivas Kandagatla *b <<= bit_offset; 130169aba794SSrinivas Kandagatla 130269aba794SSrinivas Kandagatla /* setup the first byte with lsb bits from nvmem */ 1303795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, cell->offset, &v, 1); 130450808bfcSMathieu Malaterre if (rc) 130550808bfcSMathieu Malaterre goto err; 130669aba794SSrinivas Kandagatla *b++ |= GENMASK(bit_offset - 1, 0) & v; 130769aba794SSrinivas Kandagatla 130869aba794SSrinivas Kandagatla /* setup rest of the byte if any */ 130969aba794SSrinivas Kandagatla for (i = 1; i < cell->bytes; i++) { 131069aba794SSrinivas Kandagatla /* Get last byte bits and shift them towards lsb */ 131169aba794SSrinivas Kandagatla pbits = pbyte >> (BITS_PER_BYTE - 1 - bit_offset); 131269aba794SSrinivas Kandagatla pbyte = *b; 131369aba794SSrinivas Kandagatla p = b; 131469aba794SSrinivas Kandagatla *b <<= bit_offset; 131569aba794SSrinivas Kandagatla *b++ |= pbits; 131669aba794SSrinivas Kandagatla } 131769aba794SSrinivas Kandagatla } 131869aba794SSrinivas Kandagatla 131969aba794SSrinivas Kandagatla /* if it's not end on byte boundary */ 132069aba794SSrinivas Kandagatla if ((nbits + bit_offset) % BITS_PER_BYTE) { 132169aba794SSrinivas Kandagatla /* setup the last byte with msb bits from nvmem */ 1322795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, 132369aba794SSrinivas Kandagatla cell->offset + cell->bytes - 1, &v, 1); 132450808bfcSMathieu Malaterre if (rc) 132550808bfcSMathieu Malaterre goto err; 132669aba794SSrinivas Kandagatla *p |= GENMASK(7, (nbits + bit_offset) % BITS_PER_BYTE) & v; 132769aba794SSrinivas Kandagatla 132869aba794SSrinivas Kandagatla } 132969aba794SSrinivas Kandagatla 133069aba794SSrinivas Kandagatla return buf; 133150808bfcSMathieu Malaterre err: 133250808bfcSMathieu Malaterre kfree(buf); 133350808bfcSMathieu Malaterre return ERR_PTR(rc); 133469aba794SSrinivas Kandagatla } 133569aba794SSrinivas Kandagatla 133669aba794SSrinivas Kandagatla /** 133769aba794SSrinivas Kandagatla * nvmem_cell_write() - Write to a given nvmem cell 133869aba794SSrinivas Kandagatla * 133969aba794SSrinivas Kandagatla * @cell: nvmem cell to be written. 134069aba794SSrinivas Kandagatla * @buf: Buffer to be written. 134169aba794SSrinivas Kandagatla * @len: length of buffer to be written to nvmem cell. 134269aba794SSrinivas Kandagatla * 134369aba794SSrinivas Kandagatla * Return: length of bytes written or negative on failure. 134469aba794SSrinivas Kandagatla */ 134569aba794SSrinivas Kandagatla int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len) 134669aba794SSrinivas Kandagatla { 134769aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 134869aba794SSrinivas Kandagatla int rc; 134969aba794SSrinivas Kandagatla 1350795ddd18SSrinivas Kandagatla if (!nvmem || nvmem->read_only || 135169aba794SSrinivas Kandagatla (cell->bit_offset == 0 && len != cell->bytes)) 135269aba794SSrinivas Kandagatla return -EINVAL; 135369aba794SSrinivas Kandagatla 135469aba794SSrinivas Kandagatla if (cell->bit_offset || cell->nbits) { 135569aba794SSrinivas Kandagatla buf = nvmem_cell_prepare_write_buffer(cell, buf, len); 135669aba794SSrinivas Kandagatla if (IS_ERR(buf)) 135769aba794SSrinivas Kandagatla return PTR_ERR(buf); 135869aba794SSrinivas Kandagatla } 135969aba794SSrinivas Kandagatla 1360795ddd18SSrinivas Kandagatla rc = nvmem_reg_write(nvmem, cell->offset, buf, cell->bytes); 136169aba794SSrinivas Kandagatla 136269aba794SSrinivas Kandagatla /* free the tmp buffer */ 1363ace22170SAxel Lin if (cell->bit_offset || cell->nbits) 136469aba794SSrinivas Kandagatla kfree(buf); 136569aba794SSrinivas Kandagatla 1366287980e4SArnd Bergmann if (rc) 136769aba794SSrinivas Kandagatla return rc; 136869aba794SSrinivas Kandagatla 136969aba794SSrinivas Kandagatla return len; 137069aba794SSrinivas Kandagatla } 137169aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_write); 137269aba794SSrinivas Kandagatla 13736bb317ceSYangtao Li static int nvmem_cell_read_common(struct device *dev, const char *cell_id, 13746bb317ceSYangtao Li void *val, size_t count) 13750a9b2d1cSFabrice Gasnier { 13760a9b2d1cSFabrice Gasnier struct nvmem_cell *cell; 13770a9b2d1cSFabrice Gasnier void *buf; 13780a9b2d1cSFabrice Gasnier size_t len; 13790a9b2d1cSFabrice Gasnier 13800a9b2d1cSFabrice Gasnier cell = nvmem_cell_get(dev, cell_id); 13810a9b2d1cSFabrice Gasnier if (IS_ERR(cell)) 13820a9b2d1cSFabrice Gasnier return PTR_ERR(cell); 13830a9b2d1cSFabrice Gasnier 13840a9b2d1cSFabrice Gasnier buf = nvmem_cell_read(cell, &len); 13850a9b2d1cSFabrice Gasnier if (IS_ERR(buf)) { 13860a9b2d1cSFabrice Gasnier nvmem_cell_put(cell); 13870a9b2d1cSFabrice Gasnier return PTR_ERR(buf); 13880a9b2d1cSFabrice Gasnier } 13896bb317ceSYangtao Li if (len != count) { 13900a9b2d1cSFabrice Gasnier kfree(buf); 13910a9b2d1cSFabrice Gasnier nvmem_cell_put(cell); 13920a9b2d1cSFabrice Gasnier return -EINVAL; 13930a9b2d1cSFabrice Gasnier } 13946bb317ceSYangtao Li memcpy(val, buf, count); 13950a9b2d1cSFabrice Gasnier kfree(buf); 13960a9b2d1cSFabrice Gasnier nvmem_cell_put(cell); 13970a9b2d1cSFabrice Gasnier 13980a9b2d1cSFabrice Gasnier return 0; 13990a9b2d1cSFabrice Gasnier } 14006bb317ceSYangtao Li 14016bb317ceSYangtao Li /** 14025037d368SAndreas Färber * nvmem_cell_read_u8() - Read a cell value as a u8 14035037d368SAndreas Färber * 14045037d368SAndreas Färber * @dev: Device that requests the nvmem cell. 14055037d368SAndreas Färber * @cell_id: Name of nvmem cell to read. 14065037d368SAndreas Färber * @val: pointer to output value. 14075037d368SAndreas Färber * 14085037d368SAndreas Färber * Return: 0 on success or negative errno. 14095037d368SAndreas Färber */ 14105037d368SAndreas Färber int nvmem_cell_read_u8(struct device *dev, const char *cell_id, u8 *val) 14115037d368SAndreas Färber { 14125037d368SAndreas Färber return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val)); 14135037d368SAndreas Färber } 14145037d368SAndreas Färber EXPORT_SYMBOL_GPL(nvmem_cell_read_u8); 14155037d368SAndreas Färber 14165037d368SAndreas Färber /** 14173a758071SAndreas Färber * nvmem_cell_read_u16() - Read a cell value as a u16 14186bb317ceSYangtao Li * 14196bb317ceSYangtao Li * @dev: Device that requests the nvmem cell. 14206bb317ceSYangtao Li * @cell_id: Name of nvmem cell to read. 14216bb317ceSYangtao Li * @val: pointer to output value. 14226bb317ceSYangtao Li * 14236bb317ceSYangtao Li * Return: 0 on success or negative errno. 14246bb317ceSYangtao Li */ 14256bb317ceSYangtao Li int nvmem_cell_read_u16(struct device *dev, const char *cell_id, u16 *val) 14266bb317ceSYangtao Li { 14276bb317ceSYangtao Li return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val)); 14286bb317ceSYangtao Li } 14290a9b2d1cSFabrice Gasnier EXPORT_SYMBOL_GPL(nvmem_cell_read_u16); 14300a9b2d1cSFabrice Gasnier 14310a9b2d1cSFabrice Gasnier /** 14323a758071SAndreas Färber * nvmem_cell_read_u32() - Read a cell value as a u32 1433d026d70aSLeonard Crestez * 1434d026d70aSLeonard Crestez * @dev: Device that requests the nvmem cell. 1435d026d70aSLeonard Crestez * @cell_id: Name of nvmem cell to read. 1436d026d70aSLeonard Crestez * @val: pointer to output value. 1437d026d70aSLeonard Crestez * 1438d026d70aSLeonard Crestez * Return: 0 on success or negative errno. 1439d026d70aSLeonard Crestez */ 1440d026d70aSLeonard Crestez int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val) 1441d026d70aSLeonard Crestez { 14426bb317ceSYangtao Li return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val)); 1443d026d70aSLeonard Crestez } 1444d026d70aSLeonard Crestez EXPORT_SYMBOL_GPL(nvmem_cell_read_u32); 1445d026d70aSLeonard Crestez 1446d026d70aSLeonard Crestez /** 14473a758071SAndreas Färber * nvmem_cell_read_u64() - Read a cell value as a u64 14488b977c54SYangtao Li * 14498b977c54SYangtao Li * @dev: Device that requests the nvmem cell. 14508b977c54SYangtao Li * @cell_id: Name of nvmem cell to read. 14518b977c54SYangtao Li * @val: pointer to output value. 14528b977c54SYangtao Li * 14538b977c54SYangtao Li * Return: 0 on success or negative errno. 14548b977c54SYangtao Li */ 14558b977c54SYangtao Li int nvmem_cell_read_u64(struct device *dev, const char *cell_id, u64 *val) 14568b977c54SYangtao Li { 14578b977c54SYangtao Li return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val)); 14588b977c54SYangtao Li } 14598b977c54SYangtao Li EXPORT_SYMBOL_GPL(nvmem_cell_read_u64); 14608b977c54SYangtao Li 14618b977c54SYangtao Li /** 1462e2a5402eSSrinivas Kandagatla * nvmem_device_cell_read() - Read a given nvmem device and cell 1463e2a5402eSSrinivas Kandagatla * 1464e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to read from. 1465e2a5402eSSrinivas Kandagatla * @info: nvmem cell info to be read. 1466e2a5402eSSrinivas Kandagatla * @buf: buffer pointer which will be populated on successful read. 1467e2a5402eSSrinivas Kandagatla * 1468e2a5402eSSrinivas Kandagatla * Return: length of successful bytes read on success and negative 1469e2a5402eSSrinivas Kandagatla * error code on error. 1470e2a5402eSSrinivas Kandagatla */ 1471e2a5402eSSrinivas Kandagatla ssize_t nvmem_device_cell_read(struct nvmem_device *nvmem, 1472e2a5402eSSrinivas Kandagatla struct nvmem_cell_info *info, void *buf) 1473e2a5402eSSrinivas Kandagatla { 1474e2a5402eSSrinivas Kandagatla struct nvmem_cell cell; 1475e2a5402eSSrinivas Kandagatla int rc; 1476e2a5402eSSrinivas Kandagatla ssize_t len; 1477e2a5402eSSrinivas Kandagatla 1478795ddd18SSrinivas Kandagatla if (!nvmem) 1479e2a5402eSSrinivas Kandagatla return -EINVAL; 1480e2a5402eSSrinivas Kandagatla 1481*fc9eec4dSVadym Kochan rc = nvmem_cell_info_to_nvmem_cell_nodup(nvmem, info, &cell); 1482287980e4SArnd Bergmann if (rc) 1483e2a5402eSSrinivas Kandagatla return rc; 1484e2a5402eSSrinivas Kandagatla 1485e2a5402eSSrinivas Kandagatla rc = __nvmem_cell_read(nvmem, &cell, buf, &len); 1486287980e4SArnd Bergmann if (rc) 1487e2a5402eSSrinivas Kandagatla return rc; 1488e2a5402eSSrinivas Kandagatla 1489e2a5402eSSrinivas Kandagatla return len; 1490e2a5402eSSrinivas Kandagatla } 1491e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_cell_read); 1492e2a5402eSSrinivas Kandagatla 1493e2a5402eSSrinivas Kandagatla /** 1494e2a5402eSSrinivas Kandagatla * nvmem_device_cell_write() - Write cell to a given nvmem device 1495e2a5402eSSrinivas Kandagatla * 1496e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to be written to. 149729143268SVivek Gautam * @info: nvmem cell info to be written. 1498e2a5402eSSrinivas Kandagatla * @buf: buffer to be written to cell. 1499e2a5402eSSrinivas Kandagatla * 1500e2a5402eSSrinivas Kandagatla * Return: length of bytes written or negative error code on failure. 150148f63a2cSBartosz Golaszewski */ 1502e2a5402eSSrinivas Kandagatla int nvmem_device_cell_write(struct nvmem_device *nvmem, 1503e2a5402eSSrinivas Kandagatla struct nvmem_cell_info *info, void *buf) 1504e2a5402eSSrinivas Kandagatla { 1505e2a5402eSSrinivas Kandagatla struct nvmem_cell cell; 1506e2a5402eSSrinivas Kandagatla int rc; 1507e2a5402eSSrinivas Kandagatla 1508795ddd18SSrinivas Kandagatla if (!nvmem) 1509e2a5402eSSrinivas Kandagatla return -EINVAL; 1510e2a5402eSSrinivas Kandagatla 1511*fc9eec4dSVadym Kochan rc = nvmem_cell_info_to_nvmem_cell_nodup(nvmem, info, &cell); 1512287980e4SArnd Bergmann if (rc) 1513e2a5402eSSrinivas Kandagatla return rc; 1514e2a5402eSSrinivas Kandagatla 1515e2a5402eSSrinivas Kandagatla return nvmem_cell_write(&cell, buf, cell.bytes); 1516e2a5402eSSrinivas Kandagatla } 1517e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_cell_write); 1518e2a5402eSSrinivas Kandagatla 1519e2a5402eSSrinivas Kandagatla /** 1520e2a5402eSSrinivas Kandagatla * nvmem_device_read() - Read from a given nvmem device 1521e2a5402eSSrinivas Kandagatla * 1522e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to read from. 1523e2a5402eSSrinivas Kandagatla * @offset: offset in nvmem device. 1524e2a5402eSSrinivas Kandagatla * @bytes: number of bytes to read. 1525e2a5402eSSrinivas Kandagatla * @buf: buffer pointer which will be populated on successful read. 1526e2a5402eSSrinivas Kandagatla * 1527e2a5402eSSrinivas Kandagatla * Return: length of successful bytes read on success and negative 1528e2a5402eSSrinivas Kandagatla * error code on error. 1529e2a5402eSSrinivas Kandagatla */ 1530e2a5402eSSrinivas Kandagatla int nvmem_device_read(struct nvmem_device *nvmem, 1531e2a5402eSSrinivas Kandagatla unsigned int offset, 1532e2a5402eSSrinivas Kandagatla size_t bytes, void *buf) 1533e2a5402eSSrinivas Kandagatla { 1534e2a5402eSSrinivas Kandagatla int rc; 1535e2a5402eSSrinivas Kandagatla 1536795ddd18SSrinivas Kandagatla if (!nvmem) 1537e2a5402eSSrinivas Kandagatla return -EINVAL; 1538e2a5402eSSrinivas Kandagatla 1539795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, offset, buf, bytes); 1540e2a5402eSSrinivas Kandagatla 1541287980e4SArnd Bergmann if (rc) 1542e2a5402eSSrinivas Kandagatla return rc; 1543e2a5402eSSrinivas Kandagatla 1544e2a5402eSSrinivas Kandagatla return bytes; 1545e2a5402eSSrinivas Kandagatla } 1546e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_read); 1547e2a5402eSSrinivas Kandagatla 1548e2a5402eSSrinivas Kandagatla /** 1549e2a5402eSSrinivas Kandagatla * nvmem_device_write() - Write cell to a given nvmem device 1550e2a5402eSSrinivas Kandagatla * 1551e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to be written to. 1552e2a5402eSSrinivas Kandagatla * @offset: offset in nvmem device. 1553e2a5402eSSrinivas Kandagatla * @bytes: number of bytes to write. 1554e2a5402eSSrinivas Kandagatla * @buf: buffer to be written. 1555e2a5402eSSrinivas Kandagatla * 1556e2a5402eSSrinivas Kandagatla * Return: length of bytes written or negative error code on failure. 155748f63a2cSBartosz Golaszewski */ 1558e2a5402eSSrinivas Kandagatla int nvmem_device_write(struct nvmem_device *nvmem, 1559e2a5402eSSrinivas Kandagatla unsigned int offset, 1560e2a5402eSSrinivas Kandagatla size_t bytes, void *buf) 1561e2a5402eSSrinivas Kandagatla { 1562e2a5402eSSrinivas Kandagatla int rc; 1563e2a5402eSSrinivas Kandagatla 1564795ddd18SSrinivas Kandagatla if (!nvmem) 1565e2a5402eSSrinivas Kandagatla return -EINVAL; 1566e2a5402eSSrinivas Kandagatla 1567795ddd18SSrinivas Kandagatla rc = nvmem_reg_write(nvmem, offset, buf, bytes); 1568e2a5402eSSrinivas Kandagatla 1569287980e4SArnd Bergmann if (rc) 1570e2a5402eSSrinivas Kandagatla return rc; 1571e2a5402eSSrinivas Kandagatla 1572e2a5402eSSrinivas Kandagatla 1573e2a5402eSSrinivas Kandagatla return bytes; 1574e2a5402eSSrinivas Kandagatla } 1575e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_write); 1576e2a5402eSSrinivas Kandagatla 1577d7b9fd16SBartosz Golaszewski /** 1578b985f4cbSBartosz Golaszewski * nvmem_add_cell_table() - register a table of cell info entries 1579b985f4cbSBartosz Golaszewski * 1580b985f4cbSBartosz Golaszewski * @table: table of cell info entries 1581b985f4cbSBartosz Golaszewski */ 1582b985f4cbSBartosz Golaszewski void nvmem_add_cell_table(struct nvmem_cell_table *table) 1583b985f4cbSBartosz Golaszewski { 1584b985f4cbSBartosz Golaszewski mutex_lock(&nvmem_cell_mutex); 1585b985f4cbSBartosz Golaszewski list_add_tail(&table->node, &nvmem_cell_tables); 1586b985f4cbSBartosz Golaszewski mutex_unlock(&nvmem_cell_mutex); 1587b985f4cbSBartosz Golaszewski } 1588b985f4cbSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_add_cell_table); 1589b985f4cbSBartosz Golaszewski 1590b985f4cbSBartosz Golaszewski /** 1591b985f4cbSBartosz Golaszewski * nvmem_del_cell_table() - remove a previously registered cell info table 1592b985f4cbSBartosz Golaszewski * 1593b985f4cbSBartosz Golaszewski * @table: table of cell info entries 1594b985f4cbSBartosz Golaszewski */ 1595b985f4cbSBartosz Golaszewski void nvmem_del_cell_table(struct nvmem_cell_table *table) 1596b985f4cbSBartosz Golaszewski { 1597b985f4cbSBartosz Golaszewski mutex_lock(&nvmem_cell_mutex); 1598b985f4cbSBartosz Golaszewski list_del(&table->node); 1599b985f4cbSBartosz Golaszewski mutex_unlock(&nvmem_cell_mutex); 1600b985f4cbSBartosz Golaszewski } 1601b985f4cbSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_del_cell_table); 1602b985f4cbSBartosz Golaszewski 1603b985f4cbSBartosz Golaszewski /** 1604506157beSBartosz Golaszewski * nvmem_add_cell_lookups() - register a list of cell lookup entries 1605506157beSBartosz Golaszewski * 1606506157beSBartosz Golaszewski * @entries: array of cell lookup entries 1607506157beSBartosz Golaszewski * @nentries: number of cell lookup entries in the array 1608506157beSBartosz Golaszewski */ 1609506157beSBartosz Golaszewski void nvmem_add_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries) 1610506157beSBartosz Golaszewski { 1611506157beSBartosz Golaszewski int i; 1612506157beSBartosz Golaszewski 1613506157beSBartosz Golaszewski mutex_lock(&nvmem_lookup_mutex); 1614506157beSBartosz Golaszewski for (i = 0; i < nentries; i++) 1615506157beSBartosz Golaszewski list_add_tail(&entries[i].node, &nvmem_lookup_list); 1616506157beSBartosz Golaszewski mutex_unlock(&nvmem_lookup_mutex); 1617506157beSBartosz Golaszewski } 1618506157beSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_add_cell_lookups); 1619506157beSBartosz Golaszewski 1620506157beSBartosz Golaszewski /** 1621506157beSBartosz Golaszewski * nvmem_del_cell_lookups() - remove a list of previously added cell lookup 1622506157beSBartosz Golaszewski * entries 1623506157beSBartosz Golaszewski * 1624506157beSBartosz Golaszewski * @entries: array of cell lookup entries 1625506157beSBartosz Golaszewski * @nentries: number of cell lookup entries in the array 1626506157beSBartosz Golaszewski */ 1627506157beSBartosz Golaszewski void nvmem_del_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries) 1628506157beSBartosz Golaszewski { 1629506157beSBartosz Golaszewski int i; 1630506157beSBartosz Golaszewski 1631506157beSBartosz Golaszewski mutex_lock(&nvmem_lookup_mutex); 1632506157beSBartosz Golaszewski for (i = 0; i < nentries; i++) 1633506157beSBartosz Golaszewski list_del(&entries[i].node); 1634506157beSBartosz Golaszewski mutex_unlock(&nvmem_lookup_mutex); 1635506157beSBartosz Golaszewski } 1636506157beSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_del_cell_lookups); 1637506157beSBartosz Golaszewski 1638506157beSBartosz Golaszewski /** 1639d7b9fd16SBartosz Golaszewski * nvmem_dev_name() - Get the name of a given nvmem device. 1640d7b9fd16SBartosz Golaszewski * 1641d7b9fd16SBartosz Golaszewski * @nvmem: nvmem device. 1642d7b9fd16SBartosz Golaszewski * 1643d7b9fd16SBartosz Golaszewski * Return: name of the nvmem device. 1644d7b9fd16SBartosz Golaszewski */ 1645d7b9fd16SBartosz Golaszewski const char *nvmem_dev_name(struct nvmem_device *nvmem) 1646d7b9fd16SBartosz Golaszewski { 1647d7b9fd16SBartosz Golaszewski return dev_name(&nvmem->dev); 1648d7b9fd16SBartosz Golaszewski } 1649d7b9fd16SBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_dev_name); 1650d7b9fd16SBartosz Golaszewski 1651eace75cfSSrinivas Kandagatla static int __init nvmem_init(void) 1652eace75cfSSrinivas Kandagatla { 1653eace75cfSSrinivas Kandagatla return bus_register(&nvmem_bus_type); 1654eace75cfSSrinivas Kandagatla } 1655eace75cfSSrinivas Kandagatla 1656eace75cfSSrinivas Kandagatla static void __exit nvmem_exit(void) 1657eace75cfSSrinivas Kandagatla { 1658eace75cfSSrinivas Kandagatla bus_unregister(&nvmem_bus_type); 1659eace75cfSSrinivas Kandagatla } 1660eace75cfSSrinivas Kandagatla 1661eace75cfSSrinivas Kandagatla subsys_initcall(nvmem_init); 1662eace75cfSSrinivas Kandagatla module_exit(nvmem_exit); 1663eace75cfSSrinivas Kandagatla 1664eace75cfSSrinivas Kandagatla MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org"); 1665eace75cfSSrinivas Kandagatla MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com"); 1666eace75cfSSrinivas Kandagatla MODULE_DESCRIPTION("nvmem Driver Core"); 1667eace75cfSSrinivas Kandagatla MODULE_LICENSE("GPL v2"); 1668