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> 21*84400305SSrinivas Kandagatla 22*84400305SSrinivas Kandagatla struct nvmem_device { 23*84400305SSrinivas Kandagatla struct module *owner; 24*84400305SSrinivas Kandagatla struct device dev; 25*84400305SSrinivas Kandagatla int stride; 26*84400305SSrinivas Kandagatla int word_size; 27*84400305SSrinivas Kandagatla int id; 28*84400305SSrinivas Kandagatla struct kref refcnt; 29*84400305SSrinivas Kandagatla size_t size; 30*84400305SSrinivas Kandagatla bool read_only; 31*84400305SSrinivas Kandagatla bool root_only; 32*84400305SSrinivas Kandagatla int flags; 33*84400305SSrinivas Kandagatla enum nvmem_type type; 34*84400305SSrinivas Kandagatla struct bin_attribute eeprom; 35*84400305SSrinivas Kandagatla struct device *base_dev; 36*84400305SSrinivas Kandagatla struct list_head cells; 37*84400305SSrinivas Kandagatla nvmem_reg_read_t reg_read; 38*84400305SSrinivas Kandagatla nvmem_reg_write_t reg_write; 39*84400305SSrinivas Kandagatla struct gpio_desc *wp_gpio; 40*84400305SSrinivas Kandagatla void *priv; 41*84400305SSrinivas Kandagatla }; 42*84400305SSrinivas Kandagatla 43*84400305SSrinivas Kandagatla #define to_nvmem_device(d) container_of(d, struct nvmem_device, dev) 44*84400305SSrinivas Kandagatla 45*84400305SSrinivas 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 69*84400305SSrinivas Kandagatla #ifdef CONFIG_NVMEM_SYSFS 70*84400305SSrinivas Kandagatla static const char * const nvmem_type_str[] = { 71*84400305SSrinivas Kandagatla [NVMEM_TYPE_UNKNOWN] = "Unknown", 72*84400305SSrinivas Kandagatla [NVMEM_TYPE_EEPROM] = "EEPROM", 73*84400305SSrinivas Kandagatla [NVMEM_TYPE_OTP] = "OTP", 74*84400305SSrinivas Kandagatla [NVMEM_TYPE_BATTERY_BACKED] = "Battery backed", 75*84400305SSrinivas Kandagatla }; 76*84400305SSrinivas Kandagatla 77*84400305SSrinivas Kandagatla #ifdef CONFIG_DEBUG_LOCK_ALLOC 78*84400305SSrinivas Kandagatla static struct lock_class_key eeprom_lock_key; 79*84400305SSrinivas Kandagatla #endif 80*84400305SSrinivas Kandagatla 81*84400305SSrinivas Kandagatla static ssize_t type_show(struct device *dev, 82*84400305SSrinivas Kandagatla struct device_attribute *attr, char *buf) 83*84400305SSrinivas Kandagatla { 84*84400305SSrinivas Kandagatla struct nvmem_device *nvmem = to_nvmem_device(dev); 85*84400305SSrinivas Kandagatla 86*84400305SSrinivas Kandagatla return sprintf(buf, "%s\n", nvmem_type_str[nvmem->type]); 87*84400305SSrinivas Kandagatla } 88*84400305SSrinivas Kandagatla 89*84400305SSrinivas Kandagatla static DEVICE_ATTR_RO(type); 90*84400305SSrinivas Kandagatla 91*84400305SSrinivas Kandagatla static struct attribute *nvmem_attrs[] = { 92*84400305SSrinivas Kandagatla &dev_attr_type.attr, 93*84400305SSrinivas Kandagatla NULL, 94*84400305SSrinivas Kandagatla }; 95*84400305SSrinivas Kandagatla 96*84400305SSrinivas Kandagatla static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj, 97*84400305SSrinivas Kandagatla struct bin_attribute *attr, char *buf, 98*84400305SSrinivas Kandagatla loff_t pos, size_t count) 99*84400305SSrinivas Kandagatla { 100*84400305SSrinivas Kandagatla struct device *dev; 101*84400305SSrinivas Kandagatla struct nvmem_device *nvmem; 102*84400305SSrinivas Kandagatla int rc; 103*84400305SSrinivas Kandagatla 104*84400305SSrinivas Kandagatla if (attr->private) 105*84400305SSrinivas Kandagatla dev = attr->private; 106*84400305SSrinivas Kandagatla else 107*84400305SSrinivas Kandagatla dev = container_of(kobj, struct device, kobj); 108*84400305SSrinivas Kandagatla nvmem = to_nvmem_device(dev); 109*84400305SSrinivas Kandagatla 110*84400305SSrinivas Kandagatla /* Stop the user from reading */ 111*84400305SSrinivas Kandagatla if (pos >= nvmem->size) 112*84400305SSrinivas Kandagatla return 0; 113*84400305SSrinivas Kandagatla 114*84400305SSrinivas Kandagatla if (count < nvmem->word_size) 115*84400305SSrinivas Kandagatla return -EINVAL; 116*84400305SSrinivas Kandagatla 117*84400305SSrinivas Kandagatla if (pos + count > nvmem->size) 118*84400305SSrinivas Kandagatla count = nvmem->size - pos; 119*84400305SSrinivas Kandagatla 120*84400305SSrinivas Kandagatla count = round_down(count, nvmem->word_size); 121*84400305SSrinivas Kandagatla 122*84400305SSrinivas Kandagatla if (!nvmem->reg_read) 123*84400305SSrinivas Kandagatla return -EPERM; 124*84400305SSrinivas Kandagatla 125*84400305SSrinivas Kandagatla rc = nvmem->reg_read(nvmem->priv, pos, buf, count); 126*84400305SSrinivas Kandagatla 127*84400305SSrinivas Kandagatla if (rc) 128*84400305SSrinivas Kandagatla return rc; 129*84400305SSrinivas Kandagatla 130*84400305SSrinivas Kandagatla return count; 131*84400305SSrinivas Kandagatla } 132*84400305SSrinivas Kandagatla 133*84400305SSrinivas Kandagatla static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj, 134*84400305SSrinivas Kandagatla struct bin_attribute *attr, char *buf, 135*84400305SSrinivas Kandagatla loff_t pos, size_t count) 136*84400305SSrinivas Kandagatla { 137*84400305SSrinivas Kandagatla struct device *dev; 138*84400305SSrinivas Kandagatla struct nvmem_device *nvmem; 139*84400305SSrinivas Kandagatla int rc; 140*84400305SSrinivas Kandagatla 141*84400305SSrinivas Kandagatla if (attr->private) 142*84400305SSrinivas Kandagatla dev = attr->private; 143*84400305SSrinivas Kandagatla else 144*84400305SSrinivas Kandagatla dev = container_of(kobj, struct device, kobj); 145*84400305SSrinivas Kandagatla nvmem = to_nvmem_device(dev); 146*84400305SSrinivas Kandagatla 147*84400305SSrinivas Kandagatla /* Stop the user from writing */ 148*84400305SSrinivas Kandagatla if (pos >= nvmem->size) 149*84400305SSrinivas Kandagatla return -EFBIG; 150*84400305SSrinivas Kandagatla 151*84400305SSrinivas Kandagatla if (count < nvmem->word_size) 152*84400305SSrinivas Kandagatla return -EINVAL; 153*84400305SSrinivas Kandagatla 154*84400305SSrinivas Kandagatla if (pos + count > nvmem->size) 155*84400305SSrinivas Kandagatla count = nvmem->size - pos; 156*84400305SSrinivas Kandagatla 157*84400305SSrinivas Kandagatla count = round_down(count, nvmem->word_size); 158*84400305SSrinivas Kandagatla 159*84400305SSrinivas Kandagatla if (!nvmem->reg_write) 160*84400305SSrinivas Kandagatla return -EPERM; 161*84400305SSrinivas Kandagatla 162*84400305SSrinivas Kandagatla rc = nvmem->reg_write(nvmem->priv, pos, buf, count); 163*84400305SSrinivas Kandagatla 164*84400305SSrinivas Kandagatla if (rc) 165*84400305SSrinivas Kandagatla return rc; 166*84400305SSrinivas Kandagatla 167*84400305SSrinivas Kandagatla return count; 168*84400305SSrinivas Kandagatla } 169*84400305SSrinivas Kandagatla 170*84400305SSrinivas Kandagatla static umode_t nvmem_bin_attr_is_visible(struct kobject *kobj, 171*84400305SSrinivas Kandagatla struct bin_attribute *attr, int i) 172*84400305SSrinivas Kandagatla { 173*84400305SSrinivas Kandagatla struct device *dev = container_of(kobj, struct device, kobj); 174*84400305SSrinivas Kandagatla struct nvmem_device *nvmem = to_nvmem_device(dev); 175*84400305SSrinivas Kandagatla umode_t mode = 0400; 176*84400305SSrinivas Kandagatla 177*84400305SSrinivas Kandagatla if (!nvmem->root_only) 178*84400305SSrinivas Kandagatla mode |= 0044; 179*84400305SSrinivas Kandagatla 180*84400305SSrinivas Kandagatla if (!nvmem->read_only) 181*84400305SSrinivas Kandagatla mode |= 0200; 182*84400305SSrinivas Kandagatla 183*84400305SSrinivas Kandagatla if (!nvmem->reg_write) 184*84400305SSrinivas Kandagatla mode &= ~0200; 185*84400305SSrinivas Kandagatla 186*84400305SSrinivas Kandagatla if (!nvmem->reg_read) 187*84400305SSrinivas Kandagatla mode &= ~0444; 188*84400305SSrinivas Kandagatla 189*84400305SSrinivas Kandagatla return mode; 190*84400305SSrinivas Kandagatla } 191*84400305SSrinivas Kandagatla 192*84400305SSrinivas Kandagatla /* default read/write permissions */ 193*84400305SSrinivas Kandagatla static struct bin_attribute bin_attr_rw_nvmem = { 194*84400305SSrinivas Kandagatla .attr = { 195*84400305SSrinivas Kandagatla .name = "nvmem", 196*84400305SSrinivas Kandagatla .mode = 0644, 197*84400305SSrinivas Kandagatla }, 198*84400305SSrinivas Kandagatla .read = bin_attr_nvmem_read, 199*84400305SSrinivas Kandagatla .write = bin_attr_nvmem_write, 200*84400305SSrinivas Kandagatla }; 201*84400305SSrinivas Kandagatla 202*84400305SSrinivas Kandagatla static struct bin_attribute *nvmem_bin_attributes[] = { 203*84400305SSrinivas Kandagatla &bin_attr_rw_nvmem, 204*84400305SSrinivas Kandagatla NULL, 205*84400305SSrinivas Kandagatla }; 206*84400305SSrinivas Kandagatla 207*84400305SSrinivas Kandagatla static const struct attribute_group nvmem_bin_group = { 208*84400305SSrinivas Kandagatla .bin_attrs = nvmem_bin_attributes, 209*84400305SSrinivas Kandagatla .attrs = nvmem_attrs, 210*84400305SSrinivas Kandagatla .is_bin_visible = nvmem_bin_attr_is_visible, 211*84400305SSrinivas Kandagatla }; 212*84400305SSrinivas Kandagatla 213*84400305SSrinivas Kandagatla static const struct attribute_group *nvmem_dev_groups[] = { 214*84400305SSrinivas Kandagatla &nvmem_bin_group, 215*84400305SSrinivas Kandagatla NULL, 216*84400305SSrinivas Kandagatla }; 217*84400305SSrinivas Kandagatla 218*84400305SSrinivas Kandagatla /* read only permission */ 219*84400305SSrinivas Kandagatla static struct bin_attribute bin_attr_ro_nvmem = { 220*84400305SSrinivas Kandagatla .attr = { 221*84400305SSrinivas Kandagatla .name = "nvmem", 222*84400305SSrinivas Kandagatla .mode = 0444, 223*84400305SSrinivas Kandagatla }, 224*84400305SSrinivas Kandagatla .read = bin_attr_nvmem_read, 225*84400305SSrinivas Kandagatla }; 226*84400305SSrinivas Kandagatla 227*84400305SSrinivas Kandagatla /* default read/write permissions, root only */ 228*84400305SSrinivas Kandagatla static struct bin_attribute bin_attr_rw_root_nvmem = { 229*84400305SSrinivas Kandagatla .attr = { 230*84400305SSrinivas Kandagatla .name = "nvmem", 231*84400305SSrinivas Kandagatla .mode = 0600, 232*84400305SSrinivas Kandagatla }, 233*84400305SSrinivas Kandagatla .read = bin_attr_nvmem_read, 234*84400305SSrinivas Kandagatla .write = bin_attr_nvmem_write, 235*84400305SSrinivas Kandagatla }; 236*84400305SSrinivas Kandagatla 237*84400305SSrinivas Kandagatla /* read only permission, root only */ 238*84400305SSrinivas Kandagatla static struct bin_attribute bin_attr_ro_root_nvmem = { 239*84400305SSrinivas Kandagatla .attr = { 240*84400305SSrinivas Kandagatla .name = "nvmem", 241*84400305SSrinivas Kandagatla .mode = 0400, 242*84400305SSrinivas Kandagatla }, 243*84400305SSrinivas Kandagatla .read = bin_attr_nvmem_read, 244*84400305SSrinivas Kandagatla }; 245*84400305SSrinivas Kandagatla 246*84400305SSrinivas Kandagatla /* 247*84400305SSrinivas Kandagatla * nvmem_setup_compat() - Create an additional binary entry in 248*84400305SSrinivas Kandagatla * drivers sys directory, to be backwards compatible with the older 249*84400305SSrinivas Kandagatla * drivers/misc/eeprom drivers. 250*84400305SSrinivas Kandagatla */ 251*84400305SSrinivas Kandagatla static int nvmem_sysfs_setup_compat(struct nvmem_device *nvmem, 252*84400305SSrinivas Kandagatla const struct nvmem_config *config) 253*84400305SSrinivas Kandagatla { 254*84400305SSrinivas Kandagatla int rval; 255*84400305SSrinivas Kandagatla 256*84400305SSrinivas Kandagatla if (!config->compat) 257*84400305SSrinivas Kandagatla return 0; 258*84400305SSrinivas Kandagatla 259*84400305SSrinivas Kandagatla if (!config->base_dev) 260*84400305SSrinivas Kandagatla return -EINVAL; 261*84400305SSrinivas Kandagatla 262*84400305SSrinivas Kandagatla if (nvmem->read_only) { 263*84400305SSrinivas Kandagatla if (config->root_only) 264*84400305SSrinivas Kandagatla nvmem->eeprom = bin_attr_ro_root_nvmem; 265*84400305SSrinivas Kandagatla else 266*84400305SSrinivas Kandagatla nvmem->eeprom = bin_attr_ro_nvmem; 267*84400305SSrinivas Kandagatla } else { 268*84400305SSrinivas Kandagatla if (config->root_only) 269*84400305SSrinivas Kandagatla nvmem->eeprom = bin_attr_rw_root_nvmem; 270*84400305SSrinivas Kandagatla else 271*84400305SSrinivas Kandagatla nvmem->eeprom = bin_attr_rw_nvmem; 272*84400305SSrinivas Kandagatla } 273*84400305SSrinivas Kandagatla nvmem->eeprom.attr.name = "eeprom"; 274*84400305SSrinivas Kandagatla nvmem->eeprom.size = nvmem->size; 275*84400305SSrinivas Kandagatla #ifdef CONFIG_DEBUG_LOCK_ALLOC 276*84400305SSrinivas Kandagatla nvmem->eeprom.attr.key = &eeprom_lock_key; 277*84400305SSrinivas Kandagatla #endif 278*84400305SSrinivas Kandagatla nvmem->eeprom.private = &nvmem->dev; 279*84400305SSrinivas Kandagatla nvmem->base_dev = config->base_dev; 280*84400305SSrinivas Kandagatla 281*84400305SSrinivas Kandagatla rval = device_create_bin_file(nvmem->base_dev, &nvmem->eeprom); 282*84400305SSrinivas Kandagatla if (rval) { 283*84400305SSrinivas Kandagatla dev_err(&nvmem->dev, 284*84400305SSrinivas Kandagatla "Failed to create eeprom binary file %d\n", rval); 285*84400305SSrinivas Kandagatla return rval; 286*84400305SSrinivas Kandagatla } 287*84400305SSrinivas Kandagatla 288*84400305SSrinivas Kandagatla nvmem->flags |= FLAG_COMPAT; 289*84400305SSrinivas Kandagatla 290*84400305SSrinivas Kandagatla return 0; 291*84400305SSrinivas Kandagatla } 292*84400305SSrinivas Kandagatla 293*84400305SSrinivas Kandagatla static void nvmem_sysfs_remove_compat(struct nvmem_device *nvmem, 294*84400305SSrinivas Kandagatla const struct nvmem_config *config) 295*84400305SSrinivas Kandagatla { 296*84400305SSrinivas Kandagatla if (config->compat) 297*84400305SSrinivas Kandagatla device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); 298*84400305SSrinivas Kandagatla } 299*84400305SSrinivas Kandagatla 300*84400305SSrinivas Kandagatla #else /* CONFIG_NVMEM_SYSFS */ 301*84400305SSrinivas Kandagatla 302*84400305SSrinivas Kandagatla static int nvmem_sysfs_setup_compat(struct nvmem_device *nvmem, 303*84400305SSrinivas Kandagatla const struct nvmem_config *config) 304*84400305SSrinivas Kandagatla { 305*84400305SSrinivas Kandagatla return -ENOSYS; 306*84400305SSrinivas Kandagatla } 307*84400305SSrinivas Kandagatla static void nvmem_sysfs_remove_compat(struct nvmem_device *nvmem, 308*84400305SSrinivas Kandagatla const struct nvmem_config *config) 309*84400305SSrinivas Kandagatla { 310*84400305SSrinivas Kandagatla } 311*84400305SSrinivas Kandagatla 312*84400305SSrinivas Kandagatla #endif /* CONFIG_NVMEM_SYSFS */ 313a8b44d5dSAndy Shevchenko 314795ddd18SSrinivas Kandagatla static int nvmem_reg_read(struct nvmem_device *nvmem, unsigned int offset, 315795ddd18SSrinivas Kandagatla void *val, size_t bytes) 316795ddd18SSrinivas Kandagatla { 317795ddd18SSrinivas Kandagatla if (nvmem->reg_read) 318795ddd18SSrinivas Kandagatla return nvmem->reg_read(nvmem->priv, offset, val, bytes); 319795ddd18SSrinivas Kandagatla 320795ddd18SSrinivas Kandagatla return -EINVAL; 321795ddd18SSrinivas Kandagatla } 322795ddd18SSrinivas Kandagatla 323795ddd18SSrinivas Kandagatla static int nvmem_reg_write(struct nvmem_device *nvmem, unsigned int offset, 324795ddd18SSrinivas Kandagatla void *val, size_t bytes) 325795ddd18SSrinivas Kandagatla { 3262a127da4SKhouloud Touil int ret; 3272a127da4SKhouloud Touil 3282a127da4SKhouloud Touil if (nvmem->reg_write) { 3292a127da4SKhouloud Touil gpiod_set_value_cansleep(nvmem->wp_gpio, 0); 3302a127da4SKhouloud Touil ret = nvmem->reg_write(nvmem->priv, offset, val, bytes); 3312a127da4SKhouloud Touil gpiod_set_value_cansleep(nvmem->wp_gpio, 1); 3322a127da4SKhouloud Touil return ret; 3332a127da4SKhouloud Touil } 334795ddd18SSrinivas Kandagatla 335795ddd18SSrinivas Kandagatla return -EINVAL; 336795ddd18SSrinivas Kandagatla } 337eace75cfSSrinivas Kandagatla 338eace75cfSSrinivas Kandagatla static void nvmem_release(struct device *dev) 339eace75cfSSrinivas Kandagatla { 340eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem = to_nvmem_device(dev); 341eace75cfSSrinivas Kandagatla 342eace75cfSSrinivas Kandagatla ida_simple_remove(&nvmem_ida, nvmem->id); 343a9c3766cSKhouloud Touil gpiod_put(nvmem->wp_gpio); 344eace75cfSSrinivas Kandagatla kfree(nvmem); 345eace75cfSSrinivas Kandagatla } 346eace75cfSSrinivas Kandagatla 347eace75cfSSrinivas Kandagatla static const struct device_type nvmem_provider_type = { 348eace75cfSSrinivas Kandagatla .release = nvmem_release, 349eace75cfSSrinivas Kandagatla }; 350eace75cfSSrinivas Kandagatla 351eace75cfSSrinivas Kandagatla static struct bus_type nvmem_bus_type = { 352eace75cfSSrinivas Kandagatla .name = "nvmem", 353eace75cfSSrinivas Kandagatla }; 354eace75cfSSrinivas Kandagatla 355eace75cfSSrinivas Kandagatla static void nvmem_cell_drop(struct nvmem_cell *cell) 356eace75cfSSrinivas Kandagatla { 357bee1138bSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_REMOVE, cell); 358c7235ee3SBartosz Golaszewski mutex_lock(&nvmem_mutex); 359eace75cfSSrinivas Kandagatla list_del(&cell->node); 360c7235ee3SBartosz Golaszewski mutex_unlock(&nvmem_mutex); 3610749aa25SSrinivas Kandagatla of_node_put(cell->np); 36216bb7abcSBitan Biswas kfree_const(cell->name); 363eace75cfSSrinivas Kandagatla kfree(cell); 364eace75cfSSrinivas Kandagatla } 365eace75cfSSrinivas Kandagatla 366eace75cfSSrinivas Kandagatla static void nvmem_device_remove_all_cells(const struct nvmem_device *nvmem) 367eace75cfSSrinivas Kandagatla { 3681852183eSBartosz Golaszewski struct nvmem_cell *cell, *p; 369eace75cfSSrinivas Kandagatla 370c7235ee3SBartosz Golaszewski list_for_each_entry_safe(cell, p, &nvmem->cells, node) 371eace75cfSSrinivas Kandagatla nvmem_cell_drop(cell); 372eace75cfSSrinivas Kandagatla } 373eace75cfSSrinivas Kandagatla 374eace75cfSSrinivas Kandagatla static void nvmem_cell_add(struct nvmem_cell *cell) 375eace75cfSSrinivas Kandagatla { 376c7235ee3SBartosz Golaszewski mutex_lock(&nvmem_mutex); 377c7235ee3SBartosz Golaszewski list_add_tail(&cell->node, &cell->nvmem->cells); 378c7235ee3SBartosz Golaszewski mutex_unlock(&nvmem_mutex); 379bee1138bSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_ADD, cell); 380eace75cfSSrinivas Kandagatla } 381eace75cfSSrinivas Kandagatla 382eace75cfSSrinivas Kandagatla static int nvmem_cell_info_to_nvmem_cell(struct nvmem_device *nvmem, 383eace75cfSSrinivas Kandagatla const struct nvmem_cell_info *info, 384eace75cfSSrinivas Kandagatla struct nvmem_cell *cell) 385eace75cfSSrinivas Kandagatla { 386eace75cfSSrinivas Kandagatla cell->nvmem = nvmem; 387eace75cfSSrinivas Kandagatla cell->offset = info->offset; 388eace75cfSSrinivas Kandagatla cell->bytes = info->bytes; 38916bb7abcSBitan Biswas cell->name = kstrdup_const(info->name, GFP_KERNEL); 39016bb7abcSBitan Biswas if (!cell->name) 39116bb7abcSBitan Biswas return -ENOMEM; 392eace75cfSSrinivas Kandagatla 393eace75cfSSrinivas Kandagatla cell->bit_offset = info->bit_offset; 394eace75cfSSrinivas Kandagatla cell->nbits = info->nbits; 395eace75cfSSrinivas Kandagatla 396eace75cfSSrinivas Kandagatla if (cell->nbits) 397eace75cfSSrinivas Kandagatla cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset, 398eace75cfSSrinivas Kandagatla BITS_PER_BYTE); 399eace75cfSSrinivas Kandagatla 400eace75cfSSrinivas Kandagatla if (!IS_ALIGNED(cell->offset, nvmem->stride)) { 401eace75cfSSrinivas Kandagatla dev_err(&nvmem->dev, 402eace75cfSSrinivas Kandagatla "cell %s unaligned to nvmem stride %d\n", 403eace75cfSSrinivas Kandagatla cell->name, nvmem->stride); 404eace75cfSSrinivas Kandagatla return -EINVAL; 405eace75cfSSrinivas Kandagatla } 406eace75cfSSrinivas Kandagatla 407eace75cfSSrinivas Kandagatla return 0; 408eace75cfSSrinivas Kandagatla } 409eace75cfSSrinivas Kandagatla 410b3db17e4SAndrew Lunn /** 411b3db17e4SAndrew Lunn * nvmem_add_cells() - Add cell information to an nvmem device 412b3db17e4SAndrew Lunn * 413b3db17e4SAndrew Lunn * @nvmem: nvmem device to add cells to. 414b3db17e4SAndrew Lunn * @info: nvmem cell info to add to the device 415b3db17e4SAndrew Lunn * @ncells: number of cells in info 416b3db17e4SAndrew Lunn * 417b3db17e4SAndrew Lunn * Return: 0 or negative error code on failure. 418b3db17e4SAndrew Lunn */ 419ef92ab30SSrinivas Kandagatla static int nvmem_add_cells(struct nvmem_device *nvmem, 420b3db17e4SAndrew Lunn const struct nvmem_cell_info *info, 421b3db17e4SAndrew Lunn int ncells) 422eace75cfSSrinivas Kandagatla { 423eace75cfSSrinivas Kandagatla struct nvmem_cell **cells; 424eace75cfSSrinivas Kandagatla int i, rval; 425eace75cfSSrinivas Kandagatla 426b3db17e4SAndrew Lunn cells = kcalloc(ncells, sizeof(*cells), GFP_KERNEL); 427eace75cfSSrinivas Kandagatla if (!cells) 428eace75cfSSrinivas Kandagatla return -ENOMEM; 429eace75cfSSrinivas Kandagatla 430b3db17e4SAndrew Lunn for (i = 0; i < ncells; i++) { 431eace75cfSSrinivas Kandagatla cells[i] = kzalloc(sizeof(**cells), GFP_KERNEL); 432eace75cfSSrinivas Kandagatla if (!cells[i]) { 433eace75cfSSrinivas Kandagatla rval = -ENOMEM; 434eace75cfSSrinivas Kandagatla goto err; 435eace75cfSSrinivas Kandagatla } 436eace75cfSSrinivas Kandagatla 437eace75cfSSrinivas Kandagatla rval = nvmem_cell_info_to_nvmem_cell(nvmem, &info[i], cells[i]); 438287980e4SArnd Bergmann if (rval) { 439eace75cfSSrinivas Kandagatla kfree(cells[i]); 440eace75cfSSrinivas Kandagatla goto err; 441eace75cfSSrinivas Kandagatla } 442eace75cfSSrinivas Kandagatla 443eace75cfSSrinivas Kandagatla nvmem_cell_add(cells[i]); 444eace75cfSSrinivas Kandagatla } 445eace75cfSSrinivas Kandagatla 446eace75cfSSrinivas Kandagatla /* remove tmp array */ 447eace75cfSSrinivas Kandagatla kfree(cells); 448eace75cfSSrinivas Kandagatla 449eace75cfSSrinivas Kandagatla return 0; 450eace75cfSSrinivas Kandagatla err: 451dfdf1414SRasmus Villemoes while (i--) 452eace75cfSSrinivas Kandagatla nvmem_cell_drop(cells[i]); 453eace75cfSSrinivas Kandagatla 454dfdf1414SRasmus Villemoes kfree(cells); 455dfdf1414SRasmus Villemoes 456eace75cfSSrinivas Kandagatla return rval; 457eace75cfSSrinivas Kandagatla } 458eace75cfSSrinivas Kandagatla 459bee1138bSBartosz Golaszewski /** 460bee1138bSBartosz Golaszewski * nvmem_register_notifier() - Register a notifier block for nvmem events. 461bee1138bSBartosz Golaszewski * 462bee1138bSBartosz Golaszewski * @nb: notifier block to be called on nvmem events. 463bee1138bSBartosz Golaszewski * 464bee1138bSBartosz Golaszewski * Return: 0 on success, negative error number on failure. 465bee1138bSBartosz Golaszewski */ 466bee1138bSBartosz Golaszewski int nvmem_register_notifier(struct notifier_block *nb) 467bee1138bSBartosz Golaszewski { 468bee1138bSBartosz Golaszewski return blocking_notifier_chain_register(&nvmem_notifier, nb); 469bee1138bSBartosz Golaszewski } 470bee1138bSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_register_notifier); 471bee1138bSBartosz Golaszewski 472bee1138bSBartosz Golaszewski /** 473bee1138bSBartosz Golaszewski * nvmem_unregister_notifier() - Unregister a notifier block for nvmem events. 474bee1138bSBartosz Golaszewski * 475bee1138bSBartosz Golaszewski * @nb: notifier block to be unregistered. 476bee1138bSBartosz Golaszewski * 477bee1138bSBartosz Golaszewski * Return: 0 on success, negative error number on failure. 478bee1138bSBartosz Golaszewski */ 479bee1138bSBartosz Golaszewski int nvmem_unregister_notifier(struct notifier_block *nb) 480bee1138bSBartosz Golaszewski { 481bee1138bSBartosz Golaszewski return blocking_notifier_chain_unregister(&nvmem_notifier, nb); 482bee1138bSBartosz Golaszewski } 483bee1138bSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_unregister_notifier); 484bee1138bSBartosz Golaszewski 485b985f4cbSBartosz Golaszewski static int nvmem_add_cells_from_table(struct nvmem_device *nvmem) 486b985f4cbSBartosz Golaszewski { 487b985f4cbSBartosz Golaszewski const struct nvmem_cell_info *info; 488b985f4cbSBartosz Golaszewski struct nvmem_cell_table *table; 489b985f4cbSBartosz Golaszewski struct nvmem_cell *cell; 490b985f4cbSBartosz Golaszewski int rval = 0, i; 491b985f4cbSBartosz Golaszewski 492b985f4cbSBartosz Golaszewski mutex_lock(&nvmem_cell_mutex); 493b985f4cbSBartosz Golaszewski list_for_each_entry(table, &nvmem_cell_tables, node) { 494b985f4cbSBartosz Golaszewski if (strcmp(nvmem_dev_name(nvmem), table->nvmem_name) == 0) { 495b985f4cbSBartosz Golaszewski for (i = 0; i < table->ncells; i++) { 496b985f4cbSBartosz Golaszewski info = &table->cells[i]; 497b985f4cbSBartosz Golaszewski 498b985f4cbSBartosz Golaszewski cell = kzalloc(sizeof(*cell), GFP_KERNEL); 499b985f4cbSBartosz Golaszewski if (!cell) { 500b985f4cbSBartosz Golaszewski rval = -ENOMEM; 501b985f4cbSBartosz Golaszewski goto out; 502b985f4cbSBartosz Golaszewski } 503b985f4cbSBartosz Golaszewski 504b985f4cbSBartosz Golaszewski rval = nvmem_cell_info_to_nvmem_cell(nvmem, 505b985f4cbSBartosz Golaszewski info, 506b985f4cbSBartosz Golaszewski cell); 507b985f4cbSBartosz Golaszewski if (rval) { 508b985f4cbSBartosz Golaszewski kfree(cell); 509b985f4cbSBartosz Golaszewski goto out; 510b985f4cbSBartosz Golaszewski } 511b985f4cbSBartosz Golaszewski 512b985f4cbSBartosz Golaszewski nvmem_cell_add(cell); 513b985f4cbSBartosz Golaszewski } 514b985f4cbSBartosz Golaszewski } 515b985f4cbSBartosz Golaszewski } 516b985f4cbSBartosz Golaszewski 517b985f4cbSBartosz Golaszewski out: 518b985f4cbSBartosz Golaszewski mutex_unlock(&nvmem_cell_mutex); 519b985f4cbSBartosz Golaszewski return rval; 520b985f4cbSBartosz Golaszewski } 521b985f4cbSBartosz Golaszewski 522e888d445SBartosz Golaszewski static struct nvmem_cell * 523506157beSBartosz Golaszewski nvmem_find_cell_by_name(struct nvmem_device *nvmem, const char *cell_id) 524506157beSBartosz Golaszewski { 5251c832674SAlban Bedel struct nvmem_cell *iter, *cell = NULL; 526506157beSBartosz Golaszewski 527506157beSBartosz Golaszewski mutex_lock(&nvmem_mutex); 5281c832674SAlban Bedel list_for_each_entry(iter, &nvmem->cells, node) { 5291c832674SAlban Bedel if (strcmp(cell_id, iter->name) == 0) { 5301c832674SAlban Bedel cell = iter; 531506157beSBartosz Golaszewski break; 532506157beSBartosz Golaszewski } 5331c832674SAlban Bedel } 534506157beSBartosz Golaszewski mutex_unlock(&nvmem_mutex); 535506157beSBartosz Golaszewski 536506157beSBartosz Golaszewski return cell; 537506157beSBartosz Golaszewski } 538506157beSBartosz Golaszewski 539e888d445SBartosz Golaszewski static int nvmem_add_cells_from_of(struct nvmem_device *nvmem) 540e888d445SBartosz Golaszewski { 541e888d445SBartosz Golaszewski struct device_node *parent, *child; 542e888d445SBartosz Golaszewski struct device *dev = &nvmem->dev; 543e888d445SBartosz Golaszewski struct nvmem_cell *cell; 544e888d445SBartosz Golaszewski const __be32 *addr; 545e888d445SBartosz Golaszewski int len; 546e888d445SBartosz Golaszewski 547e888d445SBartosz Golaszewski parent = dev->of_node; 548e888d445SBartosz Golaszewski 549e888d445SBartosz Golaszewski for_each_child_of_node(parent, child) { 550e888d445SBartosz Golaszewski addr = of_get_property(child, "reg", &len); 551e888d445SBartosz Golaszewski if (!addr || (len < 2 * sizeof(u32))) { 552e888d445SBartosz Golaszewski dev_err(dev, "nvmem: invalid reg on %pOF\n", child); 553e888d445SBartosz Golaszewski return -EINVAL; 554e888d445SBartosz Golaszewski } 555e888d445SBartosz Golaszewski 556e888d445SBartosz Golaszewski cell = kzalloc(sizeof(*cell), GFP_KERNEL); 557e888d445SBartosz Golaszewski if (!cell) 558e888d445SBartosz Golaszewski return -ENOMEM; 559e888d445SBartosz Golaszewski 560e888d445SBartosz Golaszewski cell->nvmem = nvmem; 5610749aa25SSrinivas Kandagatla cell->np = of_node_get(child); 562e888d445SBartosz Golaszewski cell->offset = be32_to_cpup(addr++); 563e888d445SBartosz Golaszewski cell->bytes = be32_to_cpup(addr); 564badcdff1SRob Herring cell->name = kasprintf(GFP_KERNEL, "%pOFn", child); 565e888d445SBartosz Golaszewski 566e888d445SBartosz Golaszewski addr = of_get_property(child, "bits", &len); 567e888d445SBartosz Golaszewski if (addr && len == (2 * sizeof(u32))) { 568e888d445SBartosz Golaszewski cell->bit_offset = be32_to_cpup(addr++); 569e888d445SBartosz Golaszewski cell->nbits = be32_to_cpup(addr); 570e888d445SBartosz Golaszewski } 571e888d445SBartosz Golaszewski 572e888d445SBartosz Golaszewski if (cell->nbits) 573e888d445SBartosz Golaszewski cell->bytes = DIV_ROUND_UP( 574e888d445SBartosz Golaszewski cell->nbits + cell->bit_offset, 575e888d445SBartosz Golaszewski BITS_PER_BYTE); 576e888d445SBartosz Golaszewski 577e888d445SBartosz Golaszewski if (!IS_ALIGNED(cell->offset, nvmem->stride)) { 578e888d445SBartosz Golaszewski dev_err(dev, "cell %s unaligned to nvmem stride %d\n", 579e888d445SBartosz Golaszewski cell->name, nvmem->stride); 580e888d445SBartosz Golaszewski /* Cells already added will be freed later. */ 58116bb7abcSBitan Biswas kfree_const(cell->name); 582e888d445SBartosz Golaszewski kfree(cell); 583e888d445SBartosz Golaszewski return -EINVAL; 584e888d445SBartosz Golaszewski } 585e888d445SBartosz Golaszewski 586e888d445SBartosz Golaszewski nvmem_cell_add(cell); 587e888d445SBartosz Golaszewski } 588e888d445SBartosz Golaszewski 589e888d445SBartosz Golaszewski return 0; 590e888d445SBartosz Golaszewski } 591e888d445SBartosz Golaszewski 592eace75cfSSrinivas Kandagatla /** 593eace75cfSSrinivas Kandagatla * nvmem_register() - Register a nvmem device for given nvmem_config. 594eace75cfSSrinivas Kandagatla * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem 595eace75cfSSrinivas Kandagatla * 596eace75cfSSrinivas Kandagatla * @config: nvmem device configuration with which nvmem device is created. 597eace75cfSSrinivas Kandagatla * 598eace75cfSSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device 599eace75cfSSrinivas Kandagatla * on success. 600eace75cfSSrinivas Kandagatla */ 601eace75cfSSrinivas Kandagatla 602eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem_register(const struct nvmem_config *config) 603eace75cfSSrinivas Kandagatla { 604eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem; 605eace75cfSSrinivas Kandagatla int rval; 606eace75cfSSrinivas Kandagatla 607eace75cfSSrinivas Kandagatla if (!config->dev) 608eace75cfSSrinivas Kandagatla return ERR_PTR(-EINVAL); 609eace75cfSSrinivas Kandagatla 610061a320bSSrinivas Kandagatla if (!config->reg_read && !config->reg_write) 611061a320bSSrinivas Kandagatla return ERR_PTR(-EINVAL); 612061a320bSSrinivas Kandagatla 613eace75cfSSrinivas Kandagatla nvmem = kzalloc(sizeof(*nvmem), GFP_KERNEL); 614eace75cfSSrinivas Kandagatla if (!nvmem) 615eace75cfSSrinivas Kandagatla return ERR_PTR(-ENOMEM); 616eace75cfSSrinivas Kandagatla 617eace75cfSSrinivas Kandagatla rval = ida_simple_get(&nvmem_ida, 0, 0, GFP_KERNEL); 618eace75cfSSrinivas Kandagatla if (rval < 0) { 619eace75cfSSrinivas Kandagatla kfree(nvmem); 620eace75cfSSrinivas Kandagatla return ERR_PTR(rval); 621eace75cfSSrinivas Kandagatla } 62231c6ff51SBartosz Golaszewski 6232a127da4SKhouloud Touil if (config->wp_gpio) 6242a127da4SKhouloud Touil nvmem->wp_gpio = config->wp_gpio; 6252a127da4SKhouloud Touil else 6262a127da4SKhouloud Touil nvmem->wp_gpio = gpiod_get_optional(config->dev, "wp", 6272a127da4SKhouloud Touil GPIOD_OUT_HIGH); 628f7d8d7dcSBartosz Golaszewski if (IS_ERR(nvmem->wp_gpio)) { 629f7d8d7dcSBartosz Golaszewski ida_simple_remove(&nvmem_ida, nvmem->id); 630f7d8d7dcSBartosz Golaszewski rval = PTR_ERR(nvmem->wp_gpio); 631f7d8d7dcSBartosz Golaszewski kfree(nvmem); 632f7d8d7dcSBartosz Golaszewski return ERR_PTR(rval); 633f7d8d7dcSBartosz Golaszewski } 6342a127da4SKhouloud Touil 635c1de7f43SBartosz Golaszewski kref_init(&nvmem->refcnt); 636c7235ee3SBartosz Golaszewski INIT_LIST_HEAD(&nvmem->cells); 637c1de7f43SBartosz Golaszewski 638eace75cfSSrinivas Kandagatla nvmem->id = rval; 639eace75cfSSrinivas Kandagatla nvmem->owner = config->owner; 64017eb18d6SMasahiro Yamada if (!nvmem->owner && config->dev->driver) 64117eb18d6SMasahiro Yamada nvmem->owner = config->dev->driver->owner; 64299897efdSHeiner Kallweit nvmem->stride = config->stride ?: 1; 64399897efdSHeiner Kallweit nvmem->word_size = config->word_size ?: 1; 644795ddd18SSrinivas Kandagatla nvmem->size = config->size; 645eace75cfSSrinivas Kandagatla nvmem->dev.type = &nvmem_provider_type; 646eace75cfSSrinivas Kandagatla nvmem->dev.bus = &nvmem_bus_type; 647eace75cfSSrinivas Kandagatla nvmem->dev.parent = config->dev; 648e6de179dSSrinivas Kandagatla nvmem->root_only = config->root_only; 649795ddd18SSrinivas Kandagatla nvmem->priv = config->priv; 65016688453SAlexandre Belloni nvmem->type = config->type; 651795ddd18SSrinivas Kandagatla nvmem->reg_read = config->reg_read; 652795ddd18SSrinivas Kandagatla nvmem->reg_write = config->reg_write; 653517f14d9SBartosz Golaszewski if (!config->no_of_node) 654fc2f9970SHeiner Kallweit nvmem->dev.of_node = config->dev->of_node; 655fd0f4906SAndrey Smirnov 656fd0f4906SAndrey Smirnov if (config->id == -1 && config->name) { 657fd0f4906SAndrey Smirnov dev_set_name(&nvmem->dev, "%s", config->name); 658fd0f4906SAndrey Smirnov } else { 659eace75cfSSrinivas Kandagatla dev_set_name(&nvmem->dev, "%s%d", 6605253193dSAban Bedel config->name ? : "nvmem", 6615253193dSAban Bedel config->name ? config->id : nvmem->id); 662fd0f4906SAndrey Smirnov } 663eace75cfSSrinivas Kandagatla 6641716cfe8SAlban Bedel nvmem->read_only = device_property_present(config->dev, "read-only") || 6651716cfe8SAlban Bedel config->read_only || !nvmem->reg_write; 666eace75cfSSrinivas Kandagatla 667*84400305SSrinivas Kandagatla #ifdef CONFIG_NVMEM_SYSFS 668*84400305SSrinivas Kandagatla nvmem->dev.groups = nvmem_dev_groups; 669*84400305SSrinivas Kandagatla #endif 670eace75cfSSrinivas Kandagatla 671eace75cfSSrinivas Kandagatla dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name); 672eace75cfSSrinivas Kandagatla 673f60442ddSSrinivas Kandagatla rval = device_register(&nvmem->dev); 674b6c217abSAndrew Lunn if (rval) 6753360acdfSJohan Hovold goto err_put_device; 676b6c217abSAndrew Lunn 677b6c217abSAndrew Lunn if (config->compat) { 678ae0c2d72SSrinivas Kandagatla rval = nvmem_sysfs_setup_compat(nvmem, config); 679b6c217abSAndrew Lunn if (rval) 6803360acdfSJohan Hovold goto err_device_del; 681eace75cfSSrinivas Kandagatla } 682eace75cfSSrinivas Kandagatla 683fa72d847SBartosz Golaszewski if (config->cells) { 684fa72d847SBartosz Golaszewski rval = nvmem_add_cells(nvmem, config->cells, config->ncells); 685fa72d847SBartosz Golaszewski if (rval) 686fa72d847SBartosz Golaszewski goto err_teardown_compat; 687fa72d847SBartosz Golaszewski } 688eace75cfSSrinivas Kandagatla 689b985f4cbSBartosz Golaszewski rval = nvmem_add_cells_from_table(nvmem); 690b985f4cbSBartosz Golaszewski if (rval) 691b985f4cbSBartosz Golaszewski goto err_remove_cells; 692b985f4cbSBartosz Golaszewski 693e888d445SBartosz Golaszewski rval = nvmem_add_cells_from_of(nvmem); 694e888d445SBartosz Golaszewski if (rval) 695e888d445SBartosz Golaszewski goto err_remove_cells; 696e888d445SBartosz Golaszewski 697f4853e1cSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_ADD, nvmem); 698bee1138bSBartosz Golaszewski 699eace75cfSSrinivas Kandagatla return nvmem; 7003360acdfSJohan Hovold 701b985f4cbSBartosz Golaszewski err_remove_cells: 702b985f4cbSBartosz Golaszewski nvmem_device_remove_all_cells(nvmem); 703fa72d847SBartosz Golaszewski err_teardown_compat: 704fa72d847SBartosz Golaszewski if (config->compat) 705ae0c2d72SSrinivas Kandagatla nvmem_sysfs_remove_compat(nvmem, config); 7063360acdfSJohan Hovold err_device_del: 7073360acdfSJohan Hovold device_del(&nvmem->dev); 7083360acdfSJohan Hovold err_put_device: 7093360acdfSJohan Hovold put_device(&nvmem->dev); 7103360acdfSJohan Hovold 711b6c217abSAndrew Lunn return ERR_PTR(rval); 712eace75cfSSrinivas Kandagatla } 713eace75cfSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_register); 714eace75cfSSrinivas Kandagatla 715c1de7f43SBartosz Golaszewski static void nvmem_device_release(struct kref *kref) 716c1de7f43SBartosz Golaszewski { 717c1de7f43SBartosz Golaszewski struct nvmem_device *nvmem; 718c1de7f43SBartosz Golaszewski 719c1de7f43SBartosz Golaszewski nvmem = container_of(kref, struct nvmem_device, refcnt); 720c1de7f43SBartosz Golaszewski 721bee1138bSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_REMOVE, nvmem); 722bee1138bSBartosz Golaszewski 723c1de7f43SBartosz Golaszewski if (nvmem->flags & FLAG_COMPAT) 724c1de7f43SBartosz Golaszewski device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); 725c1de7f43SBartosz Golaszewski 726c1de7f43SBartosz Golaszewski nvmem_device_remove_all_cells(nvmem); 727f60442ddSSrinivas Kandagatla device_unregister(&nvmem->dev); 728c1de7f43SBartosz Golaszewski } 729c1de7f43SBartosz Golaszewski 730eace75cfSSrinivas Kandagatla /** 731eace75cfSSrinivas Kandagatla * nvmem_unregister() - Unregister previously registered nvmem device 732eace75cfSSrinivas Kandagatla * 733eace75cfSSrinivas Kandagatla * @nvmem: Pointer to previously registered nvmem device. 734eace75cfSSrinivas Kandagatla */ 735bf58e882SBartosz Golaszewski void nvmem_unregister(struct nvmem_device *nvmem) 736eace75cfSSrinivas Kandagatla { 737c1de7f43SBartosz Golaszewski kref_put(&nvmem->refcnt, nvmem_device_release); 738eace75cfSSrinivas Kandagatla } 739eace75cfSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_unregister); 740eace75cfSSrinivas Kandagatla 741f1f50ecaSAndrey Smirnov static void devm_nvmem_release(struct device *dev, void *res) 742f1f50ecaSAndrey Smirnov { 743bf58e882SBartosz Golaszewski nvmem_unregister(*(struct nvmem_device **)res); 744f1f50ecaSAndrey Smirnov } 745f1f50ecaSAndrey Smirnov 746f1f50ecaSAndrey Smirnov /** 747f1f50ecaSAndrey Smirnov * devm_nvmem_register() - Register a managed nvmem device for given 748f1f50ecaSAndrey Smirnov * nvmem_config. 749f1f50ecaSAndrey Smirnov * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem 750f1f50ecaSAndrey Smirnov * 751b378c779SSrinivas Kandagatla * @dev: Device that uses the nvmem device. 752f1f50ecaSAndrey Smirnov * @config: nvmem device configuration with which nvmem device is created. 753f1f50ecaSAndrey Smirnov * 754f1f50ecaSAndrey Smirnov * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device 755f1f50ecaSAndrey Smirnov * on success. 756f1f50ecaSAndrey Smirnov */ 757f1f50ecaSAndrey Smirnov struct nvmem_device *devm_nvmem_register(struct device *dev, 758f1f50ecaSAndrey Smirnov const struct nvmem_config *config) 759f1f50ecaSAndrey Smirnov { 760f1f50ecaSAndrey Smirnov struct nvmem_device **ptr, *nvmem; 761f1f50ecaSAndrey Smirnov 762f1f50ecaSAndrey Smirnov ptr = devres_alloc(devm_nvmem_release, sizeof(*ptr), GFP_KERNEL); 763f1f50ecaSAndrey Smirnov if (!ptr) 764f1f50ecaSAndrey Smirnov return ERR_PTR(-ENOMEM); 765f1f50ecaSAndrey Smirnov 766f1f50ecaSAndrey Smirnov nvmem = nvmem_register(config); 767f1f50ecaSAndrey Smirnov 768f1f50ecaSAndrey Smirnov if (!IS_ERR(nvmem)) { 769f1f50ecaSAndrey Smirnov *ptr = nvmem; 770f1f50ecaSAndrey Smirnov devres_add(dev, ptr); 771f1f50ecaSAndrey Smirnov } else { 772f1f50ecaSAndrey Smirnov devres_free(ptr); 773f1f50ecaSAndrey Smirnov } 774f1f50ecaSAndrey Smirnov 775f1f50ecaSAndrey Smirnov return nvmem; 776f1f50ecaSAndrey Smirnov } 777f1f50ecaSAndrey Smirnov EXPORT_SYMBOL_GPL(devm_nvmem_register); 778f1f50ecaSAndrey Smirnov 779f1f50ecaSAndrey Smirnov static int devm_nvmem_match(struct device *dev, void *res, void *data) 780f1f50ecaSAndrey Smirnov { 781f1f50ecaSAndrey Smirnov struct nvmem_device **r = res; 782f1f50ecaSAndrey Smirnov 783f1f50ecaSAndrey Smirnov return *r == data; 784f1f50ecaSAndrey Smirnov } 785f1f50ecaSAndrey Smirnov 786f1f50ecaSAndrey Smirnov /** 787f1f50ecaSAndrey Smirnov * devm_nvmem_unregister() - Unregister previously registered managed nvmem 788f1f50ecaSAndrey Smirnov * device. 789f1f50ecaSAndrey Smirnov * 790b378c779SSrinivas Kandagatla * @dev: Device that uses the nvmem device. 791f1f50ecaSAndrey Smirnov * @nvmem: Pointer to previously registered nvmem device. 792f1f50ecaSAndrey Smirnov * 793f1f50ecaSAndrey Smirnov * Return: Will be an negative on error or a zero on success. 794f1f50ecaSAndrey Smirnov */ 795f1f50ecaSAndrey Smirnov int devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem) 796f1f50ecaSAndrey Smirnov { 797f1f50ecaSAndrey Smirnov return devres_release(dev, devm_nvmem_release, devm_nvmem_match, nvmem); 798f1f50ecaSAndrey Smirnov } 799f1f50ecaSAndrey Smirnov EXPORT_SYMBOL(devm_nvmem_unregister); 800f1f50ecaSAndrey Smirnov 8018c2a2b8cSThomas Bogendoerfer static struct nvmem_device *__nvmem_device_get(void *data, 8028c2a2b8cSThomas Bogendoerfer int (*match)(struct device *dev, const void *data)) 80369aba794SSrinivas Kandagatla { 80469aba794SSrinivas Kandagatla struct nvmem_device *nvmem = NULL; 8058c2a2b8cSThomas Bogendoerfer struct device *dev; 80669aba794SSrinivas Kandagatla 807c7235ee3SBartosz Golaszewski mutex_lock(&nvmem_mutex); 8088c2a2b8cSThomas Bogendoerfer dev = bus_find_device(&nvmem_bus_type, NULL, data, match); 8098c2a2b8cSThomas Bogendoerfer if (dev) 8108c2a2b8cSThomas Bogendoerfer nvmem = to_nvmem_device(dev); 81169aba794SSrinivas Kandagatla mutex_unlock(&nvmem_mutex); 812c7235ee3SBartosz Golaszewski if (!nvmem) 813c7235ee3SBartosz Golaszewski return ERR_PTR(-EPROBE_DEFER); 81469aba794SSrinivas Kandagatla 81569aba794SSrinivas Kandagatla if (!try_module_get(nvmem->owner)) { 81669aba794SSrinivas Kandagatla dev_err(&nvmem->dev, 81769aba794SSrinivas Kandagatla "could not increase module refcount for cell %s\n", 8185db652c9SBartosz Golaszewski nvmem_dev_name(nvmem)); 81969aba794SSrinivas Kandagatla 82073e9dc4dSAlban Bedel put_device(&nvmem->dev); 82169aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 82269aba794SSrinivas Kandagatla } 82369aba794SSrinivas Kandagatla 824c1de7f43SBartosz Golaszewski kref_get(&nvmem->refcnt); 825c1de7f43SBartosz Golaszewski 82669aba794SSrinivas Kandagatla return nvmem; 82769aba794SSrinivas Kandagatla } 82869aba794SSrinivas Kandagatla 82969aba794SSrinivas Kandagatla static void __nvmem_device_put(struct nvmem_device *nvmem) 83069aba794SSrinivas Kandagatla { 83173e9dc4dSAlban Bedel put_device(&nvmem->dev); 83269aba794SSrinivas Kandagatla module_put(nvmem->owner); 833c1de7f43SBartosz Golaszewski kref_put(&nvmem->refcnt, nvmem_device_release); 83469aba794SSrinivas Kandagatla } 83569aba794SSrinivas Kandagatla 836e701c67cSMasahiro Yamada #if IS_ENABLED(CONFIG_OF) 837e2a5402eSSrinivas Kandagatla /** 838e2a5402eSSrinivas Kandagatla * of_nvmem_device_get() - Get nvmem device from a given id 839e2a5402eSSrinivas Kandagatla * 84029143268SVivek Gautam * @np: Device tree node that uses the nvmem device. 841e2a5402eSSrinivas Kandagatla * @id: nvmem name from nvmem-names property. 842e2a5402eSSrinivas Kandagatla * 843e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device 844e2a5402eSSrinivas Kandagatla * on success. 845e2a5402eSSrinivas Kandagatla */ 846e2a5402eSSrinivas Kandagatla struct nvmem_device *of_nvmem_device_get(struct device_node *np, const char *id) 847e2a5402eSSrinivas Kandagatla { 848e2a5402eSSrinivas Kandagatla 849e2a5402eSSrinivas Kandagatla struct device_node *nvmem_np; 850d4e7fef1SAlban Bedel int index = 0; 851e2a5402eSSrinivas Kandagatla 852d4e7fef1SAlban Bedel if (id) 853e2a5402eSSrinivas Kandagatla index = of_property_match_string(np, "nvmem-names", id); 854e2a5402eSSrinivas Kandagatla 855e2a5402eSSrinivas Kandagatla nvmem_np = of_parse_phandle(np, "nvmem", index); 856e2a5402eSSrinivas Kandagatla if (!nvmem_np) 857d4e7fef1SAlban Bedel return ERR_PTR(-ENOENT); 858e2a5402eSSrinivas Kandagatla 8598c2a2b8cSThomas Bogendoerfer return __nvmem_device_get(nvmem_np, device_match_of_node); 860e2a5402eSSrinivas Kandagatla } 861e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_nvmem_device_get); 862e2a5402eSSrinivas Kandagatla #endif 863e2a5402eSSrinivas Kandagatla 864e2a5402eSSrinivas Kandagatla /** 865e2a5402eSSrinivas Kandagatla * nvmem_device_get() - Get nvmem device from a given id 866e2a5402eSSrinivas Kandagatla * 86729143268SVivek Gautam * @dev: Device that uses the nvmem device. 86829143268SVivek Gautam * @dev_name: name of the requested nvmem device. 869e2a5402eSSrinivas Kandagatla * 870e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device 871e2a5402eSSrinivas Kandagatla * on success. 872e2a5402eSSrinivas Kandagatla */ 873e2a5402eSSrinivas Kandagatla struct nvmem_device *nvmem_device_get(struct device *dev, const char *dev_name) 874e2a5402eSSrinivas Kandagatla { 875e2a5402eSSrinivas Kandagatla if (dev->of_node) { /* try dt first */ 876e2a5402eSSrinivas Kandagatla struct nvmem_device *nvmem; 877e2a5402eSSrinivas Kandagatla 878e2a5402eSSrinivas Kandagatla nvmem = of_nvmem_device_get(dev->of_node, dev_name); 879e2a5402eSSrinivas Kandagatla 880e2a5402eSSrinivas Kandagatla if (!IS_ERR(nvmem) || PTR_ERR(nvmem) == -EPROBE_DEFER) 881e2a5402eSSrinivas Kandagatla return nvmem; 882e2a5402eSSrinivas Kandagatla 883e2a5402eSSrinivas Kandagatla } 884e2a5402eSSrinivas Kandagatla 8858c2a2b8cSThomas Bogendoerfer return __nvmem_device_get((void *)dev_name, device_match_name); 886e2a5402eSSrinivas Kandagatla } 887e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_get); 888e2a5402eSSrinivas Kandagatla 8898c2a2b8cSThomas Bogendoerfer /** 8908c2a2b8cSThomas Bogendoerfer * nvmem_device_find() - Find nvmem device with matching function 8918c2a2b8cSThomas Bogendoerfer * 8928c2a2b8cSThomas Bogendoerfer * @data: Data to pass to match function 8938c2a2b8cSThomas Bogendoerfer * @match: Callback function to check device 8948c2a2b8cSThomas Bogendoerfer * 8958c2a2b8cSThomas Bogendoerfer * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device 8968c2a2b8cSThomas Bogendoerfer * on success. 8978c2a2b8cSThomas Bogendoerfer */ 8988c2a2b8cSThomas Bogendoerfer struct nvmem_device *nvmem_device_find(void *data, 8998c2a2b8cSThomas Bogendoerfer int (*match)(struct device *dev, const void *data)) 9008c2a2b8cSThomas Bogendoerfer { 9018c2a2b8cSThomas Bogendoerfer return __nvmem_device_get(data, match); 9028c2a2b8cSThomas Bogendoerfer } 9038c2a2b8cSThomas Bogendoerfer EXPORT_SYMBOL_GPL(nvmem_device_find); 9048c2a2b8cSThomas Bogendoerfer 905e2a5402eSSrinivas Kandagatla static int devm_nvmem_device_match(struct device *dev, void *res, void *data) 906e2a5402eSSrinivas Kandagatla { 907e2a5402eSSrinivas Kandagatla struct nvmem_device **nvmem = res; 908e2a5402eSSrinivas Kandagatla 909e2a5402eSSrinivas Kandagatla if (WARN_ON(!nvmem || !*nvmem)) 910e2a5402eSSrinivas Kandagatla return 0; 911e2a5402eSSrinivas Kandagatla 912e2a5402eSSrinivas Kandagatla return *nvmem == data; 913e2a5402eSSrinivas Kandagatla } 914e2a5402eSSrinivas Kandagatla 915e2a5402eSSrinivas Kandagatla static void devm_nvmem_device_release(struct device *dev, void *res) 916e2a5402eSSrinivas Kandagatla { 917e2a5402eSSrinivas Kandagatla nvmem_device_put(*(struct nvmem_device **)res); 918e2a5402eSSrinivas Kandagatla } 919e2a5402eSSrinivas Kandagatla 920e2a5402eSSrinivas Kandagatla /** 921e2a5402eSSrinivas Kandagatla * devm_nvmem_device_put() - put alredy got nvmem device 922e2a5402eSSrinivas Kandagatla * 92329143268SVivek Gautam * @dev: Device that uses the nvmem device. 924e2a5402eSSrinivas Kandagatla * @nvmem: pointer to nvmem device allocated by devm_nvmem_cell_get(), 925e2a5402eSSrinivas Kandagatla * that needs to be released. 926e2a5402eSSrinivas Kandagatla */ 927e2a5402eSSrinivas Kandagatla void devm_nvmem_device_put(struct device *dev, struct nvmem_device *nvmem) 928e2a5402eSSrinivas Kandagatla { 929e2a5402eSSrinivas Kandagatla int ret; 930e2a5402eSSrinivas Kandagatla 931e2a5402eSSrinivas Kandagatla ret = devres_release(dev, devm_nvmem_device_release, 932e2a5402eSSrinivas Kandagatla devm_nvmem_device_match, nvmem); 933e2a5402eSSrinivas Kandagatla 934e2a5402eSSrinivas Kandagatla WARN_ON(ret); 935e2a5402eSSrinivas Kandagatla } 936e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_device_put); 937e2a5402eSSrinivas Kandagatla 938e2a5402eSSrinivas Kandagatla /** 939e2a5402eSSrinivas Kandagatla * nvmem_device_put() - put alredy got nvmem device 940e2a5402eSSrinivas Kandagatla * 941e2a5402eSSrinivas Kandagatla * @nvmem: pointer to nvmem device that needs to be released. 942e2a5402eSSrinivas Kandagatla */ 943e2a5402eSSrinivas Kandagatla void nvmem_device_put(struct nvmem_device *nvmem) 944e2a5402eSSrinivas Kandagatla { 945e2a5402eSSrinivas Kandagatla __nvmem_device_put(nvmem); 946e2a5402eSSrinivas Kandagatla } 947e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_put); 948e2a5402eSSrinivas Kandagatla 949e2a5402eSSrinivas Kandagatla /** 950e2a5402eSSrinivas Kandagatla * devm_nvmem_device_get() - Get nvmem cell of device form a given id 951e2a5402eSSrinivas Kandagatla * 95229143268SVivek Gautam * @dev: Device that requests the nvmem device. 95329143268SVivek Gautam * @id: name id for the requested nvmem device. 954e2a5402eSSrinivas Kandagatla * 955e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_cell 956e2a5402eSSrinivas Kandagatla * on success. The nvmem_cell will be freed by the automatically once the 957e2a5402eSSrinivas Kandagatla * device is freed. 958e2a5402eSSrinivas Kandagatla */ 959e2a5402eSSrinivas Kandagatla struct nvmem_device *devm_nvmem_device_get(struct device *dev, const char *id) 960e2a5402eSSrinivas Kandagatla { 961e2a5402eSSrinivas Kandagatla struct nvmem_device **ptr, *nvmem; 962e2a5402eSSrinivas Kandagatla 963e2a5402eSSrinivas Kandagatla ptr = devres_alloc(devm_nvmem_device_release, sizeof(*ptr), GFP_KERNEL); 964e2a5402eSSrinivas Kandagatla if (!ptr) 965e2a5402eSSrinivas Kandagatla return ERR_PTR(-ENOMEM); 966e2a5402eSSrinivas Kandagatla 967e2a5402eSSrinivas Kandagatla nvmem = nvmem_device_get(dev, id); 968e2a5402eSSrinivas Kandagatla if (!IS_ERR(nvmem)) { 969e2a5402eSSrinivas Kandagatla *ptr = nvmem; 970e2a5402eSSrinivas Kandagatla devres_add(dev, ptr); 971e2a5402eSSrinivas Kandagatla } else { 972e2a5402eSSrinivas Kandagatla devres_free(ptr); 973e2a5402eSSrinivas Kandagatla } 974e2a5402eSSrinivas Kandagatla 975e2a5402eSSrinivas Kandagatla return nvmem; 976e2a5402eSSrinivas Kandagatla } 977e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_device_get); 978e2a5402eSSrinivas Kandagatla 979506157beSBartosz Golaszewski static struct nvmem_cell * 980506157beSBartosz Golaszewski nvmem_cell_get_from_lookup(struct device *dev, const char *con_id) 98169aba794SSrinivas Kandagatla { 982506157beSBartosz Golaszewski struct nvmem_cell *cell = ERR_PTR(-ENOENT); 983506157beSBartosz Golaszewski struct nvmem_cell_lookup *lookup; 98469aba794SSrinivas Kandagatla struct nvmem_device *nvmem; 985506157beSBartosz Golaszewski const char *dev_id; 98669aba794SSrinivas Kandagatla 987506157beSBartosz Golaszewski if (!dev) 988506157beSBartosz Golaszewski return ERR_PTR(-EINVAL); 98969aba794SSrinivas Kandagatla 990506157beSBartosz Golaszewski dev_id = dev_name(dev); 991506157beSBartosz Golaszewski 992506157beSBartosz Golaszewski mutex_lock(&nvmem_lookup_mutex); 993506157beSBartosz Golaszewski 994506157beSBartosz Golaszewski list_for_each_entry(lookup, &nvmem_lookup_list, node) { 995506157beSBartosz Golaszewski if ((strcmp(lookup->dev_id, dev_id) == 0) && 996506157beSBartosz Golaszewski (strcmp(lookup->con_id, con_id) == 0)) { 997506157beSBartosz Golaszewski /* This is the right entry. */ 9988c2a2b8cSThomas Bogendoerfer nvmem = __nvmem_device_get((void *)lookup->nvmem_name, 9998c2a2b8cSThomas Bogendoerfer device_match_name); 1000cccb3b19SBartosz Golaszewski if (IS_ERR(nvmem)) { 1001506157beSBartosz Golaszewski /* Provider may not be registered yet. */ 1002cccb3b19SBartosz Golaszewski cell = ERR_CAST(nvmem); 10039bfd8198SAlban Bedel break; 1004506157beSBartosz Golaszewski } 1005506157beSBartosz Golaszewski 1006506157beSBartosz Golaszewski cell = nvmem_find_cell_by_name(nvmem, 1007506157beSBartosz Golaszewski lookup->cell_name); 1008506157beSBartosz Golaszewski if (!cell) { 1009506157beSBartosz Golaszewski __nvmem_device_put(nvmem); 1010cccb3b19SBartosz Golaszewski cell = ERR_PTR(-ENOENT); 1011506157beSBartosz Golaszewski } 10129bfd8198SAlban Bedel break; 1013506157beSBartosz Golaszewski } 1014506157beSBartosz Golaszewski } 1015506157beSBartosz Golaszewski 1016506157beSBartosz Golaszewski mutex_unlock(&nvmem_lookup_mutex); 101769aba794SSrinivas Kandagatla return cell; 101869aba794SSrinivas Kandagatla } 101969aba794SSrinivas Kandagatla 1020e701c67cSMasahiro Yamada #if IS_ENABLED(CONFIG_OF) 10213c53e235SArnd Bergmann static struct nvmem_cell * 10220749aa25SSrinivas Kandagatla nvmem_find_cell_by_node(struct nvmem_device *nvmem, struct device_node *np) 10233c53e235SArnd Bergmann { 10241c832674SAlban Bedel struct nvmem_cell *iter, *cell = NULL; 10253c53e235SArnd Bergmann 10263c53e235SArnd Bergmann mutex_lock(&nvmem_mutex); 10271c832674SAlban Bedel list_for_each_entry(iter, &nvmem->cells, node) { 10281c832674SAlban Bedel if (np == iter->np) { 10291c832674SAlban Bedel cell = iter; 10303c53e235SArnd Bergmann break; 10313c53e235SArnd Bergmann } 10321c832674SAlban Bedel } 10333c53e235SArnd Bergmann mutex_unlock(&nvmem_mutex); 10343c53e235SArnd Bergmann 10353c53e235SArnd Bergmann return cell; 10363c53e235SArnd Bergmann } 10373c53e235SArnd Bergmann 103869aba794SSrinivas Kandagatla /** 103969aba794SSrinivas Kandagatla * of_nvmem_cell_get() - Get a nvmem cell from given device node and cell id 104069aba794SSrinivas Kandagatla * 104129143268SVivek Gautam * @np: Device tree node that uses the nvmem cell. 1042165589f0SBartosz Golaszewski * @id: nvmem cell name from nvmem-cell-names property, or NULL 1043fd0c478cSVivek Gautam * for the cell at index 0 (the lone cell with no accompanying 1044fd0c478cSVivek Gautam * nvmem-cell-names property). 104569aba794SSrinivas Kandagatla * 104669aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 104769aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 104869aba794SSrinivas Kandagatla * nvmem_cell_put(). 104969aba794SSrinivas Kandagatla */ 1050165589f0SBartosz Golaszewski struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *id) 105169aba794SSrinivas Kandagatla { 105269aba794SSrinivas Kandagatla struct device_node *cell_np, *nvmem_np; 105369aba794SSrinivas Kandagatla struct nvmem_device *nvmem; 1054e888d445SBartosz Golaszewski struct nvmem_cell *cell; 1055fd0c478cSVivek Gautam int index = 0; 105669aba794SSrinivas Kandagatla 1057fd0c478cSVivek Gautam /* if cell name exists, find index to the name */ 1058165589f0SBartosz Golaszewski if (id) 1059165589f0SBartosz Golaszewski index = of_property_match_string(np, "nvmem-cell-names", id); 106069aba794SSrinivas Kandagatla 106169aba794SSrinivas Kandagatla cell_np = of_parse_phandle(np, "nvmem-cells", index); 106269aba794SSrinivas Kandagatla if (!cell_np) 10635087cc19SAlban Bedel return ERR_PTR(-ENOENT); 106469aba794SSrinivas Kandagatla 106569aba794SSrinivas Kandagatla nvmem_np = of_get_next_parent(cell_np); 106669aba794SSrinivas Kandagatla if (!nvmem_np) 106769aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 106869aba794SSrinivas Kandagatla 10698c2a2b8cSThomas Bogendoerfer nvmem = __nvmem_device_get(nvmem_np, device_match_of_node); 1070aad8d097SMasahiro Yamada of_node_put(nvmem_np); 107169aba794SSrinivas Kandagatla if (IS_ERR(nvmem)) 107269aba794SSrinivas Kandagatla return ERR_CAST(nvmem); 107369aba794SSrinivas Kandagatla 10740749aa25SSrinivas Kandagatla cell = nvmem_find_cell_by_node(nvmem, cell_np); 107569aba794SSrinivas Kandagatla if (!cell) { 1076e888d445SBartosz Golaszewski __nvmem_device_put(nvmem); 1077e888d445SBartosz Golaszewski return ERR_PTR(-ENOENT); 107869aba794SSrinivas Kandagatla } 107969aba794SSrinivas Kandagatla 108069aba794SSrinivas Kandagatla return cell; 108169aba794SSrinivas Kandagatla } 108269aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_nvmem_cell_get); 108369aba794SSrinivas Kandagatla #endif 108469aba794SSrinivas Kandagatla 108569aba794SSrinivas Kandagatla /** 108669aba794SSrinivas Kandagatla * nvmem_cell_get() - Get nvmem cell of device form a given cell name 108769aba794SSrinivas Kandagatla * 108829143268SVivek Gautam * @dev: Device that requests the nvmem cell. 1089165589f0SBartosz Golaszewski * @id: nvmem cell name to get (this corresponds with the name from the 1090165589f0SBartosz Golaszewski * nvmem-cell-names property for DT systems and with the con_id from 1091165589f0SBartosz Golaszewski * the lookup entry for non-DT systems). 109269aba794SSrinivas Kandagatla * 109369aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 109469aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 109569aba794SSrinivas Kandagatla * nvmem_cell_put(). 109669aba794SSrinivas Kandagatla */ 1097165589f0SBartosz Golaszewski struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *id) 109869aba794SSrinivas Kandagatla { 109969aba794SSrinivas Kandagatla struct nvmem_cell *cell; 110069aba794SSrinivas Kandagatla 110169aba794SSrinivas Kandagatla if (dev->of_node) { /* try dt first */ 1102165589f0SBartosz Golaszewski cell = of_nvmem_cell_get(dev->of_node, id); 110369aba794SSrinivas Kandagatla if (!IS_ERR(cell) || PTR_ERR(cell) == -EPROBE_DEFER) 110469aba794SSrinivas Kandagatla return cell; 110569aba794SSrinivas Kandagatla } 110669aba794SSrinivas Kandagatla 1107165589f0SBartosz Golaszewski /* NULL cell id only allowed for device tree; invalid otherwise */ 1108165589f0SBartosz Golaszewski if (!id) 110987ed1405SDouglas Anderson return ERR_PTR(-EINVAL); 111087ed1405SDouglas Anderson 1111165589f0SBartosz Golaszewski return nvmem_cell_get_from_lookup(dev, id); 111269aba794SSrinivas Kandagatla } 111369aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_get); 111469aba794SSrinivas Kandagatla 111569aba794SSrinivas Kandagatla static void devm_nvmem_cell_release(struct device *dev, void *res) 111669aba794SSrinivas Kandagatla { 111769aba794SSrinivas Kandagatla nvmem_cell_put(*(struct nvmem_cell **)res); 111869aba794SSrinivas Kandagatla } 111969aba794SSrinivas Kandagatla 112069aba794SSrinivas Kandagatla /** 112169aba794SSrinivas Kandagatla * devm_nvmem_cell_get() - Get nvmem cell of device form a given id 112269aba794SSrinivas Kandagatla * 112329143268SVivek Gautam * @dev: Device that requests the nvmem cell. 112429143268SVivek Gautam * @id: nvmem cell name id to get. 112569aba794SSrinivas Kandagatla * 112669aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 112769aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 112869aba794SSrinivas Kandagatla * automatically once the device is freed. 112969aba794SSrinivas Kandagatla */ 113069aba794SSrinivas Kandagatla struct nvmem_cell *devm_nvmem_cell_get(struct device *dev, const char *id) 113169aba794SSrinivas Kandagatla { 113269aba794SSrinivas Kandagatla struct nvmem_cell **ptr, *cell; 113369aba794SSrinivas Kandagatla 113469aba794SSrinivas Kandagatla ptr = devres_alloc(devm_nvmem_cell_release, sizeof(*ptr), GFP_KERNEL); 113569aba794SSrinivas Kandagatla if (!ptr) 113669aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 113769aba794SSrinivas Kandagatla 113869aba794SSrinivas Kandagatla cell = nvmem_cell_get(dev, id); 113969aba794SSrinivas Kandagatla if (!IS_ERR(cell)) { 114069aba794SSrinivas Kandagatla *ptr = cell; 114169aba794SSrinivas Kandagatla devres_add(dev, ptr); 114269aba794SSrinivas Kandagatla } else { 114369aba794SSrinivas Kandagatla devres_free(ptr); 114469aba794SSrinivas Kandagatla } 114569aba794SSrinivas Kandagatla 114669aba794SSrinivas Kandagatla return cell; 114769aba794SSrinivas Kandagatla } 114869aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_cell_get); 114969aba794SSrinivas Kandagatla 115069aba794SSrinivas Kandagatla static int devm_nvmem_cell_match(struct device *dev, void *res, void *data) 115169aba794SSrinivas Kandagatla { 115269aba794SSrinivas Kandagatla struct nvmem_cell **c = res; 115369aba794SSrinivas Kandagatla 115469aba794SSrinivas Kandagatla if (WARN_ON(!c || !*c)) 115569aba794SSrinivas Kandagatla return 0; 115669aba794SSrinivas Kandagatla 115769aba794SSrinivas Kandagatla return *c == data; 115869aba794SSrinivas Kandagatla } 115969aba794SSrinivas Kandagatla 116069aba794SSrinivas Kandagatla /** 116169aba794SSrinivas Kandagatla * devm_nvmem_cell_put() - Release previously allocated nvmem cell 116269aba794SSrinivas Kandagatla * from devm_nvmem_cell_get. 116369aba794SSrinivas Kandagatla * 116429143268SVivek Gautam * @dev: Device that requests the nvmem cell. 116529143268SVivek Gautam * @cell: Previously allocated nvmem cell by devm_nvmem_cell_get(). 116669aba794SSrinivas Kandagatla */ 116769aba794SSrinivas Kandagatla void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell) 116869aba794SSrinivas Kandagatla { 116969aba794SSrinivas Kandagatla int ret; 117069aba794SSrinivas Kandagatla 117169aba794SSrinivas Kandagatla ret = devres_release(dev, devm_nvmem_cell_release, 117269aba794SSrinivas Kandagatla devm_nvmem_cell_match, cell); 117369aba794SSrinivas Kandagatla 117469aba794SSrinivas Kandagatla WARN_ON(ret); 117569aba794SSrinivas Kandagatla } 117669aba794SSrinivas Kandagatla EXPORT_SYMBOL(devm_nvmem_cell_put); 117769aba794SSrinivas Kandagatla 117869aba794SSrinivas Kandagatla /** 117969aba794SSrinivas Kandagatla * nvmem_cell_put() - Release previously allocated nvmem cell. 118069aba794SSrinivas Kandagatla * 118129143268SVivek Gautam * @cell: Previously allocated nvmem cell by nvmem_cell_get(). 118269aba794SSrinivas Kandagatla */ 118369aba794SSrinivas Kandagatla void nvmem_cell_put(struct nvmem_cell *cell) 118469aba794SSrinivas Kandagatla { 118569aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 118669aba794SSrinivas Kandagatla 118769aba794SSrinivas Kandagatla __nvmem_device_put(nvmem); 118869aba794SSrinivas Kandagatla } 118969aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_put); 119069aba794SSrinivas Kandagatla 1191f7c04f16SMasahiro Yamada static void nvmem_shift_read_buffer_in_place(struct nvmem_cell *cell, void *buf) 119269aba794SSrinivas Kandagatla { 119369aba794SSrinivas Kandagatla u8 *p, *b; 11942fe518feSJorge Ramirez-Ortiz int i, extra, bit_offset = cell->bit_offset; 119569aba794SSrinivas Kandagatla 119669aba794SSrinivas Kandagatla p = b = buf; 119769aba794SSrinivas Kandagatla if (bit_offset) { 119869aba794SSrinivas Kandagatla /* First shift */ 119969aba794SSrinivas Kandagatla *b++ >>= bit_offset; 120069aba794SSrinivas Kandagatla 120169aba794SSrinivas Kandagatla /* setup rest of the bytes if any */ 120269aba794SSrinivas Kandagatla for (i = 1; i < cell->bytes; i++) { 120369aba794SSrinivas Kandagatla /* Get bits from next byte and shift them towards msb */ 120469aba794SSrinivas Kandagatla *p |= *b << (BITS_PER_BYTE - bit_offset); 120569aba794SSrinivas Kandagatla 120669aba794SSrinivas Kandagatla p = b; 120769aba794SSrinivas Kandagatla *b++ >>= bit_offset; 120869aba794SSrinivas Kandagatla } 12092fe518feSJorge Ramirez-Ortiz } else { 12102fe518feSJorge Ramirez-Ortiz /* point to the msb */ 12112fe518feSJorge Ramirez-Ortiz p += cell->bytes - 1; 12122fe518feSJorge Ramirez-Ortiz } 121369aba794SSrinivas Kandagatla 121469aba794SSrinivas Kandagatla /* result fits in less bytes */ 12152fe518feSJorge Ramirez-Ortiz extra = cell->bytes - DIV_ROUND_UP(cell->nbits, BITS_PER_BYTE); 12162fe518feSJorge Ramirez-Ortiz while (--extra >= 0) 121769aba794SSrinivas Kandagatla *p-- = 0; 12182fe518feSJorge Ramirez-Ortiz 121969aba794SSrinivas Kandagatla /* clear msb bits if any leftover in the last byte */ 122069aba794SSrinivas Kandagatla *p &= GENMASK((cell->nbits%BITS_PER_BYTE) - 1, 0); 122169aba794SSrinivas Kandagatla } 122269aba794SSrinivas Kandagatla 122369aba794SSrinivas Kandagatla static int __nvmem_cell_read(struct nvmem_device *nvmem, 122469aba794SSrinivas Kandagatla struct nvmem_cell *cell, 122569aba794SSrinivas Kandagatla void *buf, size_t *len) 122669aba794SSrinivas Kandagatla { 122769aba794SSrinivas Kandagatla int rc; 122869aba794SSrinivas Kandagatla 1229795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, cell->offset, buf, cell->bytes); 123069aba794SSrinivas Kandagatla 1231287980e4SArnd Bergmann if (rc) 123269aba794SSrinivas Kandagatla return rc; 123369aba794SSrinivas Kandagatla 123469aba794SSrinivas Kandagatla /* shift bits in-place */ 1235cbf854abSAxel Lin if (cell->bit_offset || cell->nbits) 123669aba794SSrinivas Kandagatla nvmem_shift_read_buffer_in_place(cell, buf); 123769aba794SSrinivas Kandagatla 12383b4a6877SVivek Gautam if (len) 123969aba794SSrinivas Kandagatla *len = cell->bytes; 124069aba794SSrinivas Kandagatla 124169aba794SSrinivas Kandagatla return 0; 124269aba794SSrinivas Kandagatla } 124369aba794SSrinivas Kandagatla 124469aba794SSrinivas Kandagatla /** 124569aba794SSrinivas Kandagatla * nvmem_cell_read() - Read a given nvmem cell 124669aba794SSrinivas Kandagatla * 124769aba794SSrinivas Kandagatla * @cell: nvmem cell to be read. 12483b4a6877SVivek Gautam * @len: pointer to length of cell which will be populated on successful read; 12493b4a6877SVivek Gautam * can be NULL. 125069aba794SSrinivas Kandagatla * 1251b577fafcSBrian Norris * Return: ERR_PTR() on error or a valid pointer to a buffer on success. The 1252b577fafcSBrian Norris * buffer should be freed by the consumer with a kfree(). 125369aba794SSrinivas Kandagatla */ 125469aba794SSrinivas Kandagatla void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len) 125569aba794SSrinivas Kandagatla { 125669aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 125769aba794SSrinivas Kandagatla u8 *buf; 125869aba794SSrinivas Kandagatla int rc; 125969aba794SSrinivas Kandagatla 1260795ddd18SSrinivas Kandagatla if (!nvmem) 126169aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 126269aba794SSrinivas Kandagatla 126369aba794SSrinivas Kandagatla buf = kzalloc(cell->bytes, GFP_KERNEL); 126469aba794SSrinivas Kandagatla if (!buf) 126569aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 126669aba794SSrinivas Kandagatla 126769aba794SSrinivas Kandagatla rc = __nvmem_cell_read(nvmem, cell, buf, len); 1268287980e4SArnd Bergmann if (rc) { 126969aba794SSrinivas Kandagatla kfree(buf); 127069aba794SSrinivas Kandagatla return ERR_PTR(rc); 127169aba794SSrinivas Kandagatla } 127269aba794SSrinivas Kandagatla 127369aba794SSrinivas Kandagatla return buf; 127469aba794SSrinivas Kandagatla } 127569aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_read); 127669aba794SSrinivas Kandagatla 1277f7c04f16SMasahiro Yamada static void *nvmem_cell_prepare_write_buffer(struct nvmem_cell *cell, 127869aba794SSrinivas Kandagatla u8 *_buf, int len) 127969aba794SSrinivas Kandagatla { 128069aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 128169aba794SSrinivas Kandagatla int i, rc, nbits, bit_offset = cell->bit_offset; 128269aba794SSrinivas Kandagatla u8 v, *p, *buf, *b, pbyte, pbits; 128369aba794SSrinivas Kandagatla 128469aba794SSrinivas Kandagatla nbits = cell->nbits; 128569aba794SSrinivas Kandagatla buf = kzalloc(cell->bytes, GFP_KERNEL); 128669aba794SSrinivas Kandagatla if (!buf) 128769aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 128869aba794SSrinivas Kandagatla 128969aba794SSrinivas Kandagatla memcpy(buf, _buf, len); 129069aba794SSrinivas Kandagatla p = b = buf; 129169aba794SSrinivas Kandagatla 129269aba794SSrinivas Kandagatla if (bit_offset) { 129369aba794SSrinivas Kandagatla pbyte = *b; 129469aba794SSrinivas Kandagatla *b <<= bit_offset; 129569aba794SSrinivas Kandagatla 129669aba794SSrinivas Kandagatla /* setup the first byte with lsb bits from nvmem */ 1297795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, cell->offset, &v, 1); 129850808bfcSMathieu Malaterre if (rc) 129950808bfcSMathieu Malaterre goto err; 130069aba794SSrinivas Kandagatla *b++ |= GENMASK(bit_offset - 1, 0) & v; 130169aba794SSrinivas Kandagatla 130269aba794SSrinivas Kandagatla /* setup rest of the byte if any */ 130369aba794SSrinivas Kandagatla for (i = 1; i < cell->bytes; i++) { 130469aba794SSrinivas Kandagatla /* Get last byte bits and shift them towards lsb */ 130569aba794SSrinivas Kandagatla pbits = pbyte >> (BITS_PER_BYTE - 1 - bit_offset); 130669aba794SSrinivas Kandagatla pbyte = *b; 130769aba794SSrinivas Kandagatla p = b; 130869aba794SSrinivas Kandagatla *b <<= bit_offset; 130969aba794SSrinivas Kandagatla *b++ |= pbits; 131069aba794SSrinivas Kandagatla } 131169aba794SSrinivas Kandagatla } 131269aba794SSrinivas Kandagatla 131369aba794SSrinivas Kandagatla /* if it's not end on byte boundary */ 131469aba794SSrinivas Kandagatla if ((nbits + bit_offset) % BITS_PER_BYTE) { 131569aba794SSrinivas Kandagatla /* setup the last byte with msb bits from nvmem */ 1316795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, 131769aba794SSrinivas Kandagatla cell->offset + cell->bytes - 1, &v, 1); 131850808bfcSMathieu Malaterre if (rc) 131950808bfcSMathieu Malaterre goto err; 132069aba794SSrinivas Kandagatla *p |= GENMASK(7, (nbits + bit_offset) % BITS_PER_BYTE) & v; 132169aba794SSrinivas Kandagatla 132269aba794SSrinivas Kandagatla } 132369aba794SSrinivas Kandagatla 132469aba794SSrinivas Kandagatla return buf; 132550808bfcSMathieu Malaterre err: 132650808bfcSMathieu Malaterre kfree(buf); 132750808bfcSMathieu Malaterre return ERR_PTR(rc); 132869aba794SSrinivas Kandagatla } 132969aba794SSrinivas Kandagatla 133069aba794SSrinivas Kandagatla /** 133169aba794SSrinivas Kandagatla * nvmem_cell_write() - Write to a given nvmem cell 133269aba794SSrinivas Kandagatla * 133369aba794SSrinivas Kandagatla * @cell: nvmem cell to be written. 133469aba794SSrinivas Kandagatla * @buf: Buffer to be written. 133569aba794SSrinivas Kandagatla * @len: length of buffer to be written to nvmem cell. 133669aba794SSrinivas Kandagatla * 133769aba794SSrinivas Kandagatla * Return: length of bytes written or negative on failure. 133869aba794SSrinivas Kandagatla */ 133969aba794SSrinivas Kandagatla int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len) 134069aba794SSrinivas Kandagatla { 134169aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 134269aba794SSrinivas Kandagatla int rc; 134369aba794SSrinivas Kandagatla 1344795ddd18SSrinivas Kandagatla if (!nvmem || nvmem->read_only || 134569aba794SSrinivas Kandagatla (cell->bit_offset == 0 && len != cell->bytes)) 134669aba794SSrinivas Kandagatla return -EINVAL; 134769aba794SSrinivas Kandagatla 134869aba794SSrinivas Kandagatla if (cell->bit_offset || cell->nbits) { 134969aba794SSrinivas Kandagatla buf = nvmem_cell_prepare_write_buffer(cell, buf, len); 135069aba794SSrinivas Kandagatla if (IS_ERR(buf)) 135169aba794SSrinivas Kandagatla return PTR_ERR(buf); 135269aba794SSrinivas Kandagatla } 135369aba794SSrinivas Kandagatla 1354795ddd18SSrinivas Kandagatla rc = nvmem_reg_write(nvmem, cell->offset, buf, cell->bytes); 135569aba794SSrinivas Kandagatla 135669aba794SSrinivas Kandagatla /* free the tmp buffer */ 1357ace22170SAxel Lin if (cell->bit_offset || cell->nbits) 135869aba794SSrinivas Kandagatla kfree(buf); 135969aba794SSrinivas Kandagatla 1360287980e4SArnd Bergmann if (rc) 136169aba794SSrinivas Kandagatla return rc; 136269aba794SSrinivas Kandagatla 136369aba794SSrinivas Kandagatla return len; 136469aba794SSrinivas Kandagatla } 136569aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_write); 136669aba794SSrinivas Kandagatla 13676bb317ceSYangtao Li static int nvmem_cell_read_common(struct device *dev, const char *cell_id, 13686bb317ceSYangtao Li void *val, size_t count) 13690a9b2d1cSFabrice Gasnier { 13700a9b2d1cSFabrice Gasnier struct nvmem_cell *cell; 13710a9b2d1cSFabrice Gasnier void *buf; 13720a9b2d1cSFabrice Gasnier size_t len; 13730a9b2d1cSFabrice Gasnier 13740a9b2d1cSFabrice Gasnier cell = nvmem_cell_get(dev, cell_id); 13750a9b2d1cSFabrice Gasnier if (IS_ERR(cell)) 13760a9b2d1cSFabrice Gasnier return PTR_ERR(cell); 13770a9b2d1cSFabrice Gasnier 13780a9b2d1cSFabrice Gasnier buf = nvmem_cell_read(cell, &len); 13790a9b2d1cSFabrice Gasnier if (IS_ERR(buf)) { 13800a9b2d1cSFabrice Gasnier nvmem_cell_put(cell); 13810a9b2d1cSFabrice Gasnier return PTR_ERR(buf); 13820a9b2d1cSFabrice Gasnier } 13836bb317ceSYangtao Li if (len != count) { 13840a9b2d1cSFabrice Gasnier kfree(buf); 13850a9b2d1cSFabrice Gasnier nvmem_cell_put(cell); 13860a9b2d1cSFabrice Gasnier return -EINVAL; 13870a9b2d1cSFabrice Gasnier } 13886bb317ceSYangtao Li memcpy(val, buf, count); 13890a9b2d1cSFabrice Gasnier kfree(buf); 13900a9b2d1cSFabrice Gasnier nvmem_cell_put(cell); 13910a9b2d1cSFabrice Gasnier 13920a9b2d1cSFabrice Gasnier return 0; 13930a9b2d1cSFabrice Gasnier } 13946bb317ceSYangtao Li 13956bb317ceSYangtao Li /** 13966bb317ceSYangtao Li * nvmem_cell_read_u16() - Read a cell value as an u16 13976bb317ceSYangtao Li * 13986bb317ceSYangtao Li * @dev: Device that requests the nvmem cell. 13996bb317ceSYangtao Li * @cell_id: Name of nvmem cell to read. 14006bb317ceSYangtao Li * @val: pointer to output value. 14016bb317ceSYangtao Li * 14026bb317ceSYangtao Li * Return: 0 on success or negative errno. 14036bb317ceSYangtao Li */ 14046bb317ceSYangtao Li int nvmem_cell_read_u16(struct device *dev, const char *cell_id, u16 *val) 14056bb317ceSYangtao Li { 14066bb317ceSYangtao Li return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val)); 14076bb317ceSYangtao Li } 14080a9b2d1cSFabrice Gasnier EXPORT_SYMBOL_GPL(nvmem_cell_read_u16); 14090a9b2d1cSFabrice Gasnier 14100a9b2d1cSFabrice Gasnier /** 1411d026d70aSLeonard Crestez * nvmem_cell_read_u32() - Read a cell value as an u32 1412d026d70aSLeonard Crestez * 1413d026d70aSLeonard Crestez * @dev: Device that requests the nvmem cell. 1414d026d70aSLeonard Crestez * @cell_id: Name of nvmem cell to read. 1415d026d70aSLeonard Crestez * @val: pointer to output value. 1416d026d70aSLeonard Crestez * 1417d026d70aSLeonard Crestez * Return: 0 on success or negative errno. 1418d026d70aSLeonard Crestez */ 1419d026d70aSLeonard Crestez int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val) 1420d026d70aSLeonard Crestez { 14216bb317ceSYangtao Li return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val)); 1422d026d70aSLeonard Crestez } 1423d026d70aSLeonard Crestez EXPORT_SYMBOL_GPL(nvmem_cell_read_u32); 1424d026d70aSLeonard Crestez 1425d026d70aSLeonard Crestez /** 14268b977c54SYangtao Li * nvmem_cell_read_u64() - Read a cell value as an u64 14278b977c54SYangtao Li * 14288b977c54SYangtao Li * @dev: Device that requests the nvmem cell. 14298b977c54SYangtao Li * @cell_id: Name of nvmem cell to read. 14308b977c54SYangtao Li * @val: pointer to output value. 14318b977c54SYangtao Li * 14328b977c54SYangtao Li * Return: 0 on success or negative errno. 14338b977c54SYangtao Li */ 14348b977c54SYangtao Li int nvmem_cell_read_u64(struct device *dev, const char *cell_id, u64 *val) 14358b977c54SYangtao Li { 14368b977c54SYangtao Li return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val)); 14378b977c54SYangtao Li } 14388b977c54SYangtao Li EXPORT_SYMBOL_GPL(nvmem_cell_read_u64); 14398b977c54SYangtao Li 14408b977c54SYangtao Li /** 1441e2a5402eSSrinivas Kandagatla * nvmem_device_cell_read() - Read a given nvmem device and cell 1442e2a5402eSSrinivas Kandagatla * 1443e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to read from. 1444e2a5402eSSrinivas Kandagatla * @info: nvmem cell info to be read. 1445e2a5402eSSrinivas Kandagatla * @buf: buffer pointer which will be populated on successful read. 1446e2a5402eSSrinivas Kandagatla * 1447e2a5402eSSrinivas Kandagatla * Return: length of successful bytes read on success and negative 1448e2a5402eSSrinivas Kandagatla * error code on error. 1449e2a5402eSSrinivas Kandagatla */ 1450e2a5402eSSrinivas Kandagatla ssize_t nvmem_device_cell_read(struct nvmem_device *nvmem, 1451e2a5402eSSrinivas Kandagatla struct nvmem_cell_info *info, void *buf) 1452e2a5402eSSrinivas Kandagatla { 1453e2a5402eSSrinivas Kandagatla struct nvmem_cell cell; 1454e2a5402eSSrinivas Kandagatla int rc; 1455e2a5402eSSrinivas Kandagatla ssize_t len; 1456e2a5402eSSrinivas Kandagatla 1457795ddd18SSrinivas Kandagatla if (!nvmem) 1458e2a5402eSSrinivas Kandagatla return -EINVAL; 1459e2a5402eSSrinivas Kandagatla 1460e2a5402eSSrinivas Kandagatla rc = nvmem_cell_info_to_nvmem_cell(nvmem, info, &cell); 1461287980e4SArnd Bergmann if (rc) 1462e2a5402eSSrinivas Kandagatla return rc; 1463e2a5402eSSrinivas Kandagatla 1464e2a5402eSSrinivas Kandagatla rc = __nvmem_cell_read(nvmem, &cell, buf, &len); 1465287980e4SArnd Bergmann if (rc) 1466e2a5402eSSrinivas Kandagatla return rc; 1467e2a5402eSSrinivas Kandagatla 1468e2a5402eSSrinivas Kandagatla return len; 1469e2a5402eSSrinivas Kandagatla } 1470e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_cell_read); 1471e2a5402eSSrinivas Kandagatla 1472e2a5402eSSrinivas Kandagatla /** 1473e2a5402eSSrinivas Kandagatla * nvmem_device_cell_write() - Write cell to a given nvmem device 1474e2a5402eSSrinivas Kandagatla * 1475e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to be written to. 147629143268SVivek Gautam * @info: nvmem cell info to be written. 1477e2a5402eSSrinivas Kandagatla * @buf: buffer to be written to cell. 1478e2a5402eSSrinivas Kandagatla * 1479e2a5402eSSrinivas Kandagatla * Return: length of bytes written or negative error code on failure. 148048f63a2cSBartosz Golaszewski */ 1481e2a5402eSSrinivas Kandagatla int nvmem_device_cell_write(struct nvmem_device *nvmem, 1482e2a5402eSSrinivas Kandagatla struct nvmem_cell_info *info, void *buf) 1483e2a5402eSSrinivas Kandagatla { 1484e2a5402eSSrinivas Kandagatla struct nvmem_cell cell; 1485e2a5402eSSrinivas Kandagatla int rc; 1486e2a5402eSSrinivas Kandagatla 1487795ddd18SSrinivas Kandagatla if (!nvmem) 1488e2a5402eSSrinivas Kandagatla return -EINVAL; 1489e2a5402eSSrinivas Kandagatla 1490e2a5402eSSrinivas Kandagatla rc = nvmem_cell_info_to_nvmem_cell(nvmem, info, &cell); 1491287980e4SArnd Bergmann if (rc) 1492e2a5402eSSrinivas Kandagatla return rc; 1493e2a5402eSSrinivas Kandagatla 1494e2a5402eSSrinivas Kandagatla return nvmem_cell_write(&cell, buf, cell.bytes); 1495e2a5402eSSrinivas Kandagatla } 1496e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_cell_write); 1497e2a5402eSSrinivas Kandagatla 1498e2a5402eSSrinivas Kandagatla /** 1499e2a5402eSSrinivas Kandagatla * nvmem_device_read() - Read from a given nvmem device 1500e2a5402eSSrinivas Kandagatla * 1501e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to read from. 1502e2a5402eSSrinivas Kandagatla * @offset: offset in nvmem device. 1503e2a5402eSSrinivas Kandagatla * @bytes: number of bytes to read. 1504e2a5402eSSrinivas Kandagatla * @buf: buffer pointer which will be populated on successful read. 1505e2a5402eSSrinivas Kandagatla * 1506e2a5402eSSrinivas Kandagatla * Return: length of successful bytes read on success and negative 1507e2a5402eSSrinivas Kandagatla * error code on error. 1508e2a5402eSSrinivas Kandagatla */ 1509e2a5402eSSrinivas Kandagatla int nvmem_device_read(struct nvmem_device *nvmem, 1510e2a5402eSSrinivas Kandagatla unsigned int offset, 1511e2a5402eSSrinivas Kandagatla size_t bytes, void *buf) 1512e2a5402eSSrinivas Kandagatla { 1513e2a5402eSSrinivas Kandagatla int rc; 1514e2a5402eSSrinivas Kandagatla 1515795ddd18SSrinivas Kandagatla if (!nvmem) 1516e2a5402eSSrinivas Kandagatla return -EINVAL; 1517e2a5402eSSrinivas Kandagatla 1518795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, offset, buf, bytes); 1519e2a5402eSSrinivas Kandagatla 1520287980e4SArnd Bergmann if (rc) 1521e2a5402eSSrinivas Kandagatla return rc; 1522e2a5402eSSrinivas Kandagatla 1523e2a5402eSSrinivas Kandagatla return bytes; 1524e2a5402eSSrinivas Kandagatla } 1525e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_read); 1526e2a5402eSSrinivas Kandagatla 1527e2a5402eSSrinivas Kandagatla /** 1528e2a5402eSSrinivas Kandagatla * nvmem_device_write() - Write cell to a given nvmem device 1529e2a5402eSSrinivas Kandagatla * 1530e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to be written to. 1531e2a5402eSSrinivas Kandagatla * @offset: offset in nvmem device. 1532e2a5402eSSrinivas Kandagatla * @bytes: number of bytes to write. 1533e2a5402eSSrinivas Kandagatla * @buf: buffer to be written. 1534e2a5402eSSrinivas Kandagatla * 1535e2a5402eSSrinivas Kandagatla * Return: length of bytes written or negative error code on failure. 153648f63a2cSBartosz Golaszewski */ 1537e2a5402eSSrinivas Kandagatla int nvmem_device_write(struct nvmem_device *nvmem, 1538e2a5402eSSrinivas Kandagatla unsigned int offset, 1539e2a5402eSSrinivas Kandagatla size_t bytes, void *buf) 1540e2a5402eSSrinivas Kandagatla { 1541e2a5402eSSrinivas Kandagatla int rc; 1542e2a5402eSSrinivas Kandagatla 1543795ddd18SSrinivas Kandagatla if (!nvmem) 1544e2a5402eSSrinivas Kandagatla return -EINVAL; 1545e2a5402eSSrinivas Kandagatla 1546795ddd18SSrinivas Kandagatla rc = nvmem_reg_write(nvmem, offset, buf, bytes); 1547e2a5402eSSrinivas Kandagatla 1548287980e4SArnd Bergmann if (rc) 1549e2a5402eSSrinivas Kandagatla return rc; 1550e2a5402eSSrinivas Kandagatla 1551e2a5402eSSrinivas Kandagatla 1552e2a5402eSSrinivas Kandagatla return bytes; 1553e2a5402eSSrinivas Kandagatla } 1554e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_write); 1555e2a5402eSSrinivas Kandagatla 1556d7b9fd16SBartosz Golaszewski /** 1557b985f4cbSBartosz Golaszewski * nvmem_add_cell_table() - register a table of cell info entries 1558b985f4cbSBartosz Golaszewski * 1559b985f4cbSBartosz Golaszewski * @table: table of cell info entries 1560b985f4cbSBartosz Golaszewski */ 1561b985f4cbSBartosz Golaszewski void nvmem_add_cell_table(struct nvmem_cell_table *table) 1562b985f4cbSBartosz Golaszewski { 1563b985f4cbSBartosz Golaszewski mutex_lock(&nvmem_cell_mutex); 1564b985f4cbSBartosz Golaszewski list_add_tail(&table->node, &nvmem_cell_tables); 1565b985f4cbSBartosz Golaszewski mutex_unlock(&nvmem_cell_mutex); 1566b985f4cbSBartosz Golaszewski } 1567b985f4cbSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_add_cell_table); 1568b985f4cbSBartosz Golaszewski 1569b985f4cbSBartosz Golaszewski /** 1570b985f4cbSBartosz Golaszewski * nvmem_del_cell_table() - remove a previously registered cell info table 1571b985f4cbSBartosz Golaszewski * 1572b985f4cbSBartosz Golaszewski * @table: table of cell info entries 1573b985f4cbSBartosz Golaszewski */ 1574b985f4cbSBartosz Golaszewski void nvmem_del_cell_table(struct nvmem_cell_table *table) 1575b985f4cbSBartosz Golaszewski { 1576b985f4cbSBartosz Golaszewski mutex_lock(&nvmem_cell_mutex); 1577b985f4cbSBartosz Golaszewski list_del(&table->node); 1578b985f4cbSBartosz Golaszewski mutex_unlock(&nvmem_cell_mutex); 1579b985f4cbSBartosz Golaszewski } 1580b985f4cbSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_del_cell_table); 1581b985f4cbSBartosz Golaszewski 1582b985f4cbSBartosz Golaszewski /** 1583506157beSBartosz Golaszewski * nvmem_add_cell_lookups() - register a list of cell lookup entries 1584506157beSBartosz Golaszewski * 1585506157beSBartosz Golaszewski * @entries: array of cell lookup entries 1586506157beSBartosz Golaszewski * @nentries: number of cell lookup entries in the array 1587506157beSBartosz Golaszewski */ 1588506157beSBartosz Golaszewski void nvmem_add_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries) 1589506157beSBartosz Golaszewski { 1590506157beSBartosz Golaszewski int i; 1591506157beSBartosz Golaszewski 1592506157beSBartosz Golaszewski mutex_lock(&nvmem_lookup_mutex); 1593506157beSBartosz Golaszewski for (i = 0; i < nentries; i++) 1594506157beSBartosz Golaszewski list_add_tail(&entries[i].node, &nvmem_lookup_list); 1595506157beSBartosz Golaszewski mutex_unlock(&nvmem_lookup_mutex); 1596506157beSBartosz Golaszewski } 1597506157beSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_add_cell_lookups); 1598506157beSBartosz Golaszewski 1599506157beSBartosz Golaszewski /** 1600506157beSBartosz Golaszewski * nvmem_del_cell_lookups() - remove a list of previously added cell lookup 1601506157beSBartosz Golaszewski * entries 1602506157beSBartosz Golaszewski * 1603506157beSBartosz Golaszewski * @entries: array of cell lookup entries 1604506157beSBartosz Golaszewski * @nentries: number of cell lookup entries in the array 1605506157beSBartosz Golaszewski */ 1606506157beSBartosz Golaszewski void nvmem_del_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries) 1607506157beSBartosz Golaszewski { 1608506157beSBartosz Golaszewski int i; 1609506157beSBartosz Golaszewski 1610506157beSBartosz Golaszewski mutex_lock(&nvmem_lookup_mutex); 1611506157beSBartosz Golaszewski for (i = 0; i < nentries; i++) 1612506157beSBartosz Golaszewski list_del(&entries[i].node); 1613506157beSBartosz Golaszewski mutex_unlock(&nvmem_lookup_mutex); 1614506157beSBartosz Golaszewski } 1615506157beSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_del_cell_lookups); 1616506157beSBartosz Golaszewski 1617506157beSBartosz Golaszewski /** 1618d7b9fd16SBartosz Golaszewski * nvmem_dev_name() - Get the name of a given nvmem device. 1619d7b9fd16SBartosz Golaszewski * 1620d7b9fd16SBartosz Golaszewski * @nvmem: nvmem device. 1621d7b9fd16SBartosz Golaszewski * 1622d7b9fd16SBartosz Golaszewski * Return: name of the nvmem device. 1623d7b9fd16SBartosz Golaszewski */ 1624d7b9fd16SBartosz Golaszewski const char *nvmem_dev_name(struct nvmem_device *nvmem) 1625d7b9fd16SBartosz Golaszewski { 1626d7b9fd16SBartosz Golaszewski return dev_name(&nvmem->dev); 1627d7b9fd16SBartosz Golaszewski } 1628d7b9fd16SBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_dev_name); 1629d7b9fd16SBartosz Golaszewski 1630eace75cfSSrinivas Kandagatla static int __init nvmem_init(void) 1631eace75cfSSrinivas Kandagatla { 1632eace75cfSSrinivas Kandagatla return bus_register(&nvmem_bus_type); 1633eace75cfSSrinivas Kandagatla } 1634eace75cfSSrinivas Kandagatla 1635eace75cfSSrinivas Kandagatla static void __exit nvmem_exit(void) 1636eace75cfSSrinivas Kandagatla { 1637eace75cfSSrinivas Kandagatla bus_unregister(&nvmem_bus_type); 1638eace75cfSSrinivas Kandagatla } 1639eace75cfSSrinivas Kandagatla 1640eace75cfSSrinivas Kandagatla subsys_initcall(nvmem_init); 1641eace75cfSSrinivas Kandagatla module_exit(nvmem_exit); 1642eace75cfSSrinivas Kandagatla 1643eace75cfSSrinivas Kandagatla MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org"); 1644eace75cfSSrinivas Kandagatla MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com"); 1645eace75cfSSrinivas Kandagatla MODULE_DESCRIPTION("nvmem Driver Core"); 1646eace75cfSSrinivas Kandagatla MODULE_LICENSE("GPL v2"); 1647