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> 18eace75cfSSrinivas Kandagatla #include <linux/of.h> 19eace75cfSSrinivas Kandagatla #include <linux/slab.h> 20eace75cfSSrinivas Kandagatla 21eace75cfSSrinivas Kandagatla struct nvmem_device { 22eace75cfSSrinivas Kandagatla struct module *owner; 23eace75cfSSrinivas Kandagatla struct device dev; 24eace75cfSSrinivas Kandagatla int stride; 25eace75cfSSrinivas Kandagatla int word_size; 26eace75cfSSrinivas Kandagatla int id; 27c1de7f43SBartosz Golaszewski struct kref refcnt; 28eace75cfSSrinivas Kandagatla size_t size; 29eace75cfSSrinivas Kandagatla bool read_only; 30b6c217abSAndrew Lunn int flags; 3116688453SAlexandre Belloni enum nvmem_type type; 32b6c217abSAndrew Lunn struct bin_attribute eeprom; 33b6c217abSAndrew Lunn struct device *base_dev; 34c7235ee3SBartosz Golaszewski struct list_head cells; 35795ddd18SSrinivas Kandagatla nvmem_reg_read_t reg_read; 36795ddd18SSrinivas Kandagatla nvmem_reg_write_t reg_write; 37795ddd18SSrinivas Kandagatla void *priv; 38eace75cfSSrinivas Kandagatla }; 39eace75cfSSrinivas Kandagatla 40b6c217abSAndrew Lunn #define FLAG_COMPAT BIT(0) 41b6c217abSAndrew Lunn 42eace75cfSSrinivas Kandagatla struct nvmem_cell { 43eace75cfSSrinivas Kandagatla const char *name; 44eace75cfSSrinivas Kandagatla int offset; 45eace75cfSSrinivas Kandagatla int bytes; 46eace75cfSSrinivas Kandagatla int bit_offset; 47eace75cfSSrinivas Kandagatla int nbits; 480749aa25SSrinivas Kandagatla struct device_node *np; 49eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem; 50eace75cfSSrinivas Kandagatla struct list_head node; 51eace75cfSSrinivas Kandagatla }; 52eace75cfSSrinivas Kandagatla 53eace75cfSSrinivas Kandagatla static DEFINE_MUTEX(nvmem_mutex); 54eace75cfSSrinivas Kandagatla static DEFINE_IDA(nvmem_ida); 55eace75cfSSrinivas Kandagatla 56b985f4cbSBartosz Golaszewski static DEFINE_MUTEX(nvmem_cell_mutex); 57b985f4cbSBartosz Golaszewski static LIST_HEAD(nvmem_cell_tables); 58b985f4cbSBartosz Golaszewski 59506157beSBartosz Golaszewski static DEFINE_MUTEX(nvmem_lookup_mutex); 60506157beSBartosz Golaszewski static LIST_HEAD(nvmem_lookup_list); 61506157beSBartosz Golaszewski 62bee1138bSBartosz Golaszewski static BLOCKING_NOTIFIER_HEAD(nvmem_notifier); 63bee1138bSBartosz Golaszewski 64*a8b44d5dSAndy Shevchenko static const char * const nvmem_type_str[] = { 65*a8b44d5dSAndy Shevchenko [NVMEM_TYPE_UNKNOWN] = "Unknown", 66*a8b44d5dSAndy Shevchenko [NVMEM_TYPE_EEPROM] = "EEPROM", 67*a8b44d5dSAndy Shevchenko [NVMEM_TYPE_OTP] = "OTP", 68*a8b44d5dSAndy Shevchenko [NVMEM_TYPE_BATTERY_BACKED] = "Battery backed", 69*a8b44d5dSAndy Shevchenko }; 70*a8b44d5dSAndy Shevchenko 71b6c217abSAndrew Lunn #ifdef CONFIG_DEBUG_LOCK_ALLOC 72b6c217abSAndrew Lunn static struct lock_class_key eeprom_lock_key; 73b6c217abSAndrew Lunn #endif 74b6c217abSAndrew Lunn 75eace75cfSSrinivas Kandagatla #define to_nvmem_device(d) container_of(d, struct nvmem_device, dev) 76795ddd18SSrinivas Kandagatla static int nvmem_reg_read(struct nvmem_device *nvmem, unsigned int offset, 77795ddd18SSrinivas Kandagatla void *val, size_t bytes) 78795ddd18SSrinivas Kandagatla { 79795ddd18SSrinivas Kandagatla if (nvmem->reg_read) 80795ddd18SSrinivas Kandagatla return nvmem->reg_read(nvmem->priv, offset, val, bytes); 81795ddd18SSrinivas Kandagatla 82795ddd18SSrinivas Kandagatla return -EINVAL; 83795ddd18SSrinivas Kandagatla } 84795ddd18SSrinivas Kandagatla 85795ddd18SSrinivas Kandagatla static int nvmem_reg_write(struct nvmem_device *nvmem, unsigned int offset, 86795ddd18SSrinivas Kandagatla void *val, size_t bytes) 87795ddd18SSrinivas Kandagatla { 88795ddd18SSrinivas Kandagatla if (nvmem->reg_write) 89795ddd18SSrinivas Kandagatla return nvmem->reg_write(nvmem->priv, offset, val, bytes); 90795ddd18SSrinivas Kandagatla 91795ddd18SSrinivas Kandagatla return -EINVAL; 92795ddd18SSrinivas Kandagatla } 93eace75cfSSrinivas Kandagatla 9416688453SAlexandre Belloni static ssize_t type_show(struct device *dev, 9516688453SAlexandre Belloni struct device_attribute *attr, char *buf) 9616688453SAlexandre Belloni { 9716688453SAlexandre Belloni struct nvmem_device *nvmem = to_nvmem_device(dev); 9816688453SAlexandre Belloni 9916688453SAlexandre Belloni return sprintf(buf, "%s\n", nvmem_type_str[nvmem->type]); 10016688453SAlexandre Belloni } 10116688453SAlexandre Belloni 10216688453SAlexandre Belloni static DEVICE_ATTR_RO(type); 10316688453SAlexandre Belloni 10416688453SAlexandre Belloni static struct attribute *nvmem_attrs[] = { 10516688453SAlexandre Belloni &dev_attr_type.attr, 10616688453SAlexandre Belloni NULL, 10716688453SAlexandre Belloni }; 10816688453SAlexandre Belloni 109eace75cfSSrinivas Kandagatla static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj, 110eace75cfSSrinivas Kandagatla struct bin_attribute *attr, 111eace75cfSSrinivas Kandagatla char *buf, loff_t pos, size_t count) 112eace75cfSSrinivas Kandagatla { 113b6c217abSAndrew Lunn struct device *dev; 114b6c217abSAndrew Lunn struct nvmem_device *nvmem; 115eace75cfSSrinivas Kandagatla int rc; 116eace75cfSSrinivas Kandagatla 117b6c217abSAndrew Lunn if (attr->private) 118b6c217abSAndrew Lunn dev = attr->private; 119b6c217abSAndrew Lunn else 120b6c217abSAndrew Lunn dev = container_of(kobj, struct device, kobj); 121b6c217abSAndrew Lunn nvmem = to_nvmem_device(dev); 122b6c217abSAndrew Lunn 123eace75cfSSrinivas Kandagatla /* Stop the user from reading */ 1247c806883SZhengShunQian if (pos >= nvmem->size) 125eace75cfSSrinivas Kandagatla return 0; 126eace75cfSSrinivas Kandagatla 127313a72ffSSrinivas Kandagatla if (count < nvmem->word_size) 128313a72ffSSrinivas Kandagatla return -EINVAL; 129313a72ffSSrinivas Kandagatla 130eace75cfSSrinivas Kandagatla if (pos + count > nvmem->size) 131eace75cfSSrinivas Kandagatla count = nvmem->size - pos; 132eace75cfSSrinivas Kandagatla 133eace75cfSSrinivas Kandagatla count = round_down(count, nvmem->word_size); 134eace75cfSSrinivas Kandagatla 135795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, pos, buf, count); 136eace75cfSSrinivas Kandagatla 137287980e4SArnd Bergmann if (rc) 138eace75cfSSrinivas Kandagatla return rc; 139eace75cfSSrinivas Kandagatla 140eace75cfSSrinivas Kandagatla return count; 141eace75cfSSrinivas Kandagatla } 142eace75cfSSrinivas Kandagatla 143eace75cfSSrinivas Kandagatla static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj, 144eace75cfSSrinivas Kandagatla struct bin_attribute *attr, 145eace75cfSSrinivas Kandagatla char *buf, loff_t pos, size_t count) 146eace75cfSSrinivas Kandagatla { 147b6c217abSAndrew Lunn struct device *dev; 148b6c217abSAndrew Lunn struct nvmem_device *nvmem; 149eace75cfSSrinivas Kandagatla int rc; 150eace75cfSSrinivas Kandagatla 151b6c217abSAndrew Lunn if (attr->private) 152b6c217abSAndrew Lunn dev = attr->private; 153b6c217abSAndrew Lunn else 154b6c217abSAndrew Lunn dev = container_of(kobj, struct device, kobj); 155b6c217abSAndrew Lunn nvmem = to_nvmem_device(dev); 156b6c217abSAndrew Lunn 157eace75cfSSrinivas Kandagatla /* Stop the user from writing */ 1587c806883SZhengShunQian if (pos >= nvmem->size) 15938b0774cSGuy Shapiro return -EFBIG; 160eace75cfSSrinivas Kandagatla 161313a72ffSSrinivas Kandagatla if (count < nvmem->word_size) 162313a72ffSSrinivas Kandagatla return -EINVAL; 163313a72ffSSrinivas Kandagatla 164eace75cfSSrinivas Kandagatla if (pos + count > nvmem->size) 165eace75cfSSrinivas Kandagatla count = nvmem->size - pos; 166eace75cfSSrinivas Kandagatla 167eace75cfSSrinivas Kandagatla count = round_down(count, nvmem->word_size); 168eace75cfSSrinivas Kandagatla 169795ddd18SSrinivas Kandagatla rc = nvmem_reg_write(nvmem, pos, buf, count); 170eace75cfSSrinivas Kandagatla 171287980e4SArnd Bergmann if (rc) 172eace75cfSSrinivas Kandagatla return rc; 173eace75cfSSrinivas Kandagatla 174eace75cfSSrinivas Kandagatla return count; 175eace75cfSSrinivas Kandagatla } 176eace75cfSSrinivas Kandagatla 177eace75cfSSrinivas Kandagatla /* default read/write permissions */ 178eace75cfSSrinivas Kandagatla static struct bin_attribute bin_attr_rw_nvmem = { 179eace75cfSSrinivas Kandagatla .attr = { 180eace75cfSSrinivas Kandagatla .name = "nvmem", 181e7e07f4fSBartosz Golaszewski .mode = 0644, 182eace75cfSSrinivas Kandagatla }, 183eace75cfSSrinivas Kandagatla .read = bin_attr_nvmem_read, 184eace75cfSSrinivas Kandagatla .write = bin_attr_nvmem_write, 185eace75cfSSrinivas Kandagatla }; 186eace75cfSSrinivas Kandagatla 187eace75cfSSrinivas Kandagatla static struct bin_attribute *nvmem_bin_rw_attributes[] = { 188eace75cfSSrinivas Kandagatla &bin_attr_rw_nvmem, 189eace75cfSSrinivas Kandagatla NULL, 190eace75cfSSrinivas Kandagatla }; 191eace75cfSSrinivas Kandagatla 192eace75cfSSrinivas Kandagatla static const struct attribute_group nvmem_bin_rw_group = { 193eace75cfSSrinivas Kandagatla .bin_attrs = nvmem_bin_rw_attributes, 19416688453SAlexandre Belloni .attrs = nvmem_attrs, 195eace75cfSSrinivas Kandagatla }; 196eace75cfSSrinivas Kandagatla 197eace75cfSSrinivas Kandagatla static const struct attribute_group *nvmem_rw_dev_groups[] = { 198eace75cfSSrinivas Kandagatla &nvmem_bin_rw_group, 199eace75cfSSrinivas Kandagatla NULL, 200eace75cfSSrinivas Kandagatla }; 201eace75cfSSrinivas Kandagatla 202eace75cfSSrinivas Kandagatla /* read only permission */ 203eace75cfSSrinivas Kandagatla static struct bin_attribute bin_attr_ro_nvmem = { 204eace75cfSSrinivas Kandagatla .attr = { 205eace75cfSSrinivas Kandagatla .name = "nvmem", 206e7e07f4fSBartosz Golaszewski .mode = 0444, 207eace75cfSSrinivas Kandagatla }, 208eace75cfSSrinivas Kandagatla .read = bin_attr_nvmem_read, 209eace75cfSSrinivas Kandagatla }; 210eace75cfSSrinivas Kandagatla 211eace75cfSSrinivas Kandagatla static struct bin_attribute *nvmem_bin_ro_attributes[] = { 212eace75cfSSrinivas Kandagatla &bin_attr_ro_nvmem, 213eace75cfSSrinivas Kandagatla NULL, 214eace75cfSSrinivas Kandagatla }; 215eace75cfSSrinivas Kandagatla 216eace75cfSSrinivas Kandagatla static const struct attribute_group nvmem_bin_ro_group = { 217eace75cfSSrinivas Kandagatla .bin_attrs = nvmem_bin_ro_attributes, 21816688453SAlexandre Belloni .attrs = nvmem_attrs, 219eace75cfSSrinivas Kandagatla }; 220eace75cfSSrinivas Kandagatla 221eace75cfSSrinivas Kandagatla static const struct attribute_group *nvmem_ro_dev_groups[] = { 222eace75cfSSrinivas Kandagatla &nvmem_bin_ro_group, 223eace75cfSSrinivas Kandagatla NULL, 224eace75cfSSrinivas Kandagatla }; 225eace75cfSSrinivas Kandagatla 226811b0d65SAndrew Lunn /* default read/write permissions, root only */ 227811b0d65SAndrew Lunn static struct bin_attribute bin_attr_rw_root_nvmem = { 228811b0d65SAndrew Lunn .attr = { 229811b0d65SAndrew Lunn .name = "nvmem", 230e7e07f4fSBartosz Golaszewski .mode = 0600, 231811b0d65SAndrew Lunn }, 232811b0d65SAndrew Lunn .read = bin_attr_nvmem_read, 233811b0d65SAndrew Lunn .write = bin_attr_nvmem_write, 234811b0d65SAndrew Lunn }; 235811b0d65SAndrew Lunn 236811b0d65SAndrew Lunn static struct bin_attribute *nvmem_bin_rw_root_attributes[] = { 237811b0d65SAndrew Lunn &bin_attr_rw_root_nvmem, 238811b0d65SAndrew Lunn NULL, 239811b0d65SAndrew Lunn }; 240811b0d65SAndrew Lunn 241811b0d65SAndrew Lunn static const struct attribute_group nvmem_bin_rw_root_group = { 242811b0d65SAndrew Lunn .bin_attrs = nvmem_bin_rw_root_attributes, 24316688453SAlexandre Belloni .attrs = nvmem_attrs, 244811b0d65SAndrew Lunn }; 245811b0d65SAndrew Lunn 246811b0d65SAndrew Lunn static const struct attribute_group *nvmem_rw_root_dev_groups[] = { 247811b0d65SAndrew Lunn &nvmem_bin_rw_root_group, 248811b0d65SAndrew Lunn NULL, 249811b0d65SAndrew Lunn }; 250811b0d65SAndrew Lunn 251811b0d65SAndrew Lunn /* read only permission, root only */ 252811b0d65SAndrew Lunn static struct bin_attribute bin_attr_ro_root_nvmem = { 253811b0d65SAndrew Lunn .attr = { 254811b0d65SAndrew Lunn .name = "nvmem", 255e7e07f4fSBartosz Golaszewski .mode = 0400, 256811b0d65SAndrew Lunn }, 257811b0d65SAndrew Lunn .read = bin_attr_nvmem_read, 258811b0d65SAndrew Lunn }; 259811b0d65SAndrew Lunn 260811b0d65SAndrew Lunn static struct bin_attribute *nvmem_bin_ro_root_attributes[] = { 261811b0d65SAndrew Lunn &bin_attr_ro_root_nvmem, 262811b0d65SAndrew Lunn NULL, 263811b0d65SAndrew Lunn }; 264811b0d65SAndrew Lunn 265811b0d65SAndrew Lunn static const struct attribute_group nvmem_bin_ro_root_group = { 266811b0d65SAndrew Lunn .bin_attrs = nvmem_bin_ro_root_attributes, 26716688453SAlexandre Belloni .attrs = nvmem_attrs, 268811b0d65SAndrew Lunn }; 269811b0d65SAndrew Lunn 270811b0d65SAndrew Lunn static const struct attribute_group *nvmem_ro_root_dev_groups[] = { 271811b0d65SAndrew Lunn &nvmem_bin_ro_root_group, 272811b0d65SAndrew Lunn NULL, 273811b0d65SAndrew Lunn }; 274811b0d65SAndrew Lunn 275eace75cfSSrinivas Kandagatla static void nvmem_release(struct device *dev) 276eace75cfSSrinivas Kandagatla { 277eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem = to_nvmem_device(dev); 278eace75cfSSrinivas Kandagatla 279eace75cfSSrinivas Kandagatla ida_simple_remove(&nvmem_ida, nvmem->id); 280eace75cfSSrinivas Kandagatla kfree(nvmem); 281eace75cfSSrinivas Kandagatla } 282eace75cfSSrinivas Kandagatla 283eace75cfSSrinivas Kandagatla static const struct device_type nvmem_provider_type = { 284eace75cfSSrinivas Kandagatla .release = nvmem_release, 285eace75cfSSrinivas Kandagatla }; 286eace75cfSSrinivas Kandagatla 287eace75cfSSrinivas Kandagatla static struct bus_type nvmem_bus_type = { 288eace75cfSSrinivas Kandagatla .name = "nvmem", 289eace75cfSSrinivas Kandagatla }; 290eace75cfSSrinivas Kandagatla 291eace75cfSSrinivas Kandagatla static int of_nvmem_match(struct device *dev, void *nvmem_np) 292eace75cfSSrinivas Kandagatla { 293eace75cfSSrinivas Kandagatla return dev->of_node == nvmem_np; 294eace75cfSSrinivas Kandagatla } 295eace75cfSSrinivas Kandagatla 296eace75cfSSrinivas Kandagatla static struct nvmem_device *of_nvmem_find(struct device_node *nvmem_np) 297eace75cfSSrinivas Kandagatla { 298eace75cfSSrinivas Kandagatla struct device *d; 299eace75cfSSrinivas Kandagatla 300eace75cfSSrinivas Kandagatla if (!nvmem_np) 301eace75cfSSrinivas Kandagatla return NULL; 302eace75cfSSrinivas Kandagatla 303eace75cfSSrinivas Kandagatla d = bus_find_device(&nvmem_bus_type, NULL, nvmem_np, of_nvmem_match); 304eace75cfSSrinivas Kandagatla 305eace75cfSSrinivas Kandagatla if (!d) 306eace75cfSSrinivas Kandagatla return NULL; 307eace75cfSSrinivas Kandagatla 308eace75cfSSrinivas Kandagatla return to_nvmem_device(d); 309eace75cfSSrinivas Kandagatla } 310eace75cfSSrinivas Kandagatla 311506157beSBartosz Golaszewski static struct nvmem_device *nvmem_find(const char *name) 312506157beSBartosz Golaszewski { 313506157beSBartosz Golaszewski struct device *d; 314506157beSBartosz Golaszewski 315506157beSBartosz Golaszewski d = bus_find_device_by_name(&nvmem_bus_type, NULL, name); 316506157beSBartosz Golaszewski 317506157beSBartosz Golaszewski if (!d) 318506157beSBartosz Golaszewski return NULL; 319506157beSBartosz Golaszewski 320506157beSBartosz Golaszewski return to_nvmem_device(d); 321506157beSBartosz Golaszewski } 322506157beSBartosz Golaszewski 323eace75cfSSrinivas Kandagatla static void nvmem_cell_drop(struct nvmem_cell *cell) 324eace75cfSSrinivas Kandagatla { 325bee1138bSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_REMOVE, cell); 326c7235ee3SBartosz Golaszewski mutex_lock(&nvmem_mutex); 327eace75cfSSrinivas Kandagatla list_del(&cell->node); 328c7235ee3SBartosz Golaszewski mutex_unlock(&nvmem_mutex); 3290749aa25SSrinivas Kandagatla of_node_put(cell->np); 330badcdff1SRob Herring kfree(cell->name); 331eace75cfSSrinivas Kandagatla kfree(cell); 332eace75cfSSrinivas Kandagatla } 333eace75cfSSrinivas Kandagatla 334eace75cfSSrinivas Kandagatla static void nvmem_device_remove_all_cells(const struct nvmem_device *nvmem) 335eace75cfSSrinivas Kandagatla { 3361852183eSBartosz Golaszewski struct nvmem_cell *cell, *p; 337eace75cfSSrinivas Kandagatla 338c7235ee3SBartosz Golaszewski list_for_each_entry_safe(cell, p, &nvmem->cells, node) 339eace75cfSSrinivas Kandagatla nvmem_cell_drop(cell); 340eace75cfSSrinivas Kandagatla } 341eace75cfSSrinivas Kandagatla 342eace75cfSSrinivas Kandagatla static void nvmem_cell_add(struct nvmem_cell *cell) 343eace75cfSSrinivas Kandagatla { 344c7235ee3SBartosz Golaszewski mutex_lock(&nvmem_mutex); 345c7235ee3SBartosz Golaszewski list_add_tail(&cell->node, &cell->nvmem->cells); 346c7235ee3SBartosz Golaszewski mutex_unlock(&nvmem_mutex); 347bee1138bSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_ADD, cell); 348eace75cfSSrinivas Kandagatla } 349eace75cfSSrinivas Kandagatla 350eace75cfSSrinivas Kandagatla static int nvmem_cell_info_to_nvmem_cell(struct nvmem_device *nvmem, 351eace75cfSSrinivas Kandagatla const struct nvmem_cell_info *info, 352eace75cfSSrinivas Kandagatla struct nvmem_cell *cell) 353eace75cfSSrinivas Kandagatla { 354eace75cfSSrinivas Kandagatla cell->nvmem = nvmem; 355eace75cfSSrinivas Kandagatla cell->offset = info->offset; 356eace75cfSSrinivas Kandagatla cell->bytes = info->bytes; 357eace75cfSSrinivas Kandagatla cell->name = info->name; 358eace75cfSSrinivas Kandagatla 359eace75cfSSrinivas Kandagatla cell->bit_offset = info->bit_offset; 360eace75cfSSrinivas Kandagatla cell->nbits = info->nbits; 361eace75cfSSrinivas Kandagatla 362eace75cfSSrinivas Kandagatla if (cell->nbits) 363eace75cfSSrinivas Kandagatla cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset, 364eace75cfSSrinivas Kandagatla BITS_PER_BYTE); 365eace75cfSSrinivas Kandagatla 366eace75cfSSrinivas Kandagatla if (!IS_ALIGNED(cell->offset, nvmem->stride)) { 367eace75cfSSrinivas Kandagatla dev_err(&nvmem->dev, 368eace75cfSSrinivas Kandagatla "cell %s unaligned to nvmem stride %d\n", 369eace75cfSSrinivas Kandagatla cell->name, nvmem->stride); 370eace75cfSSrinivas Kandagatla return -EINVAL; 371eace75cfSSrinivas Kandagatla } 372eace75cfSSrinivas Kandagatla 373eace75cfSSrinivas Kandagatla return 0; 374eace75cfSSrinivas Kandagatla } 375eace75cfSSrinivas Kandagatla 376b3db17e4SAndrew Lunn /** 377b3db17e4SAndrew Lunn * nvmem_add_cells() - Add cell information to an nvmem device 378b3db17e4SAndrew Lunn * 379b3db17e4SAndrew Lunn * @nvmem: nvmem device to add cells to. 380b3db17e4SAndrew Lunn * @info: nvmem cell info to add to the device 381b3db17e4SAndrew Lunn * @ncells: number of cells in info 382b3db17e4SAndrew Lunn * 383b3db17e4SAndrew Lunn * Return: 0 or negative error code on failure. 384b3db17e4SAndrew Lunn */ 385ef92ab30SSrinivas Kandagatla static int nvmem_add_cells(struct nvmem_device *nvmem, 386b3db17e4SAndrew Lunn const struct nvmem_cell_info *info, 387b3db17e4SAndrew Lunn int ncells) 388eace75cfSSrinivas Kandagatla { 389eace75cfSSrinivas Kandagatla struct nvmem_cell **cells; 390eace75cfSSrinivas Kandagatla int i, rval; 391eace75cfSSrinivas Kandagatla 392b3db17e4SAndrew Lunn cells = kcalloc(ncells, sizeof(*cells), GFP_KERNEL); 393eace75cfSSrinivas Kandagatla if (!cells) 394eace75cfSSrinivas Kandagatla return -ENOMEM; 395eace75cfSSrinivas Kandagatla 396b3db17e4SAndrew Lunn for (i = 0; i < ncells; i++) { 397eace75cfSSrinivas Kandagatla cells[i] = kzalloc(sizeof(**cells), GFP_KERNEL); 398eace75cfSSrinivas Kandagatla if (!cells[i]) { 399eace75cfSSrinivas Kandagatla rval = -ENOMEM; 400eace75cfSSrinivas Kandagatla goto err; 401eace75cfSSrinivas Kandagatla } 402eace75cfSSrinivas Kandagatla 403eace75cfSSrinivas Kandagatla rval = nvmem_cell_info_to_nvmem_cell(nvmem, &info[i], cells[i]); 404287980e4SArnd Bergmann if (rval) { 405eace75cfSSrinivas Kandagatla kfree(cells[i]); 406eace75cfSSrinivas Kandagatla goto err; 407eace75cfSSrinivas Kandagatla } 408eace75cfSSrinivas Kandagatla 409eace75cfSSrinivas Kandagatla nvmem_cell_add(cells[i]); 410eace75cfSSrinivas Kandagatla } 411eace75cfSSrinivas Kandagatla 412eace75cfSSrinivas Kandagatla /* remove tmp array */ 413eace75cfSSrinivas Kandagatla kfree(cells); 414eace75cfSSrinivas Kandagatla 415eace75cfSSrinivas Kandagatla return 0; 416eace75cfSSrinivas Kandagatla err: 417dfdf1414SRasmus Villemoes while (i--) 418eace75cfSSrinivas Kandagatla nvmem_cell_drop(cells[i]); 419eace75cfSSrinivas Kandagatla 420dfdf1414SRasmus Villemoes kfree(cells); 421dfdf1414SRasmus Villemoes 422eace75cfSSrinivas Kandagatla return rval; 423eace75cfSSrinivas Kandagatla } 424eace75cfSSrinivas Kandagatla 425b6c217abSAndrew Lunn /* 426b6c217abSAndrew Lunn * nvmem_setup_compat() - Create an additional binary entry in 427b6c217abSAndrew Lunn * drivers sys directory, to be backwards compatible with the older 428b6c217abSAndrew Lunn * drivers/misc/eeprom drivers. 429b6c217abSAndrew Lunn */ 430b6c217abSAndrew Lunn static int nvmem_setup_compat(struct nvmem_device *nvmem, 431b6c217abSAndrew Lunn const struct nvmem_config *config) 432b6c217abSAndrew Lunn { 433b6c217abSAndrew Lunn int rval; 434b6c217abSAndrew Lunn 435b6c217abSAndrew Lunn if (!config->base_dev) 436b6c217abSAndrew Lunn return -EINVAL; 437b6c217abSAndrew Lunn 438b6c217abSAndrew Lunn if (nvmem->read_only) 439b6c217abSAndrew Lunn nvmem->eeprom = bin_attr_ro_root_nvmem; 440b6c217abSAndrew Lunn else 441b6c217abSAndrew Lunn nvmem->eeprom = bin_attr_rw_root_nvmem; 442b6c217abSAndrew Lunn nvmem->eeprom.attr.name = "eeprom"; 443b6c217abSAndrew Lunn nvmem->eeprom.size = nvmem->size; 444b6c217abSAndrew Lunn #ifdef CONFIG_DEBUG_LOCK_ALLOC 445b6c217abSAndrew Lunn nvmem->eeprom.attr.key = &eeprom_lock_key; 446b6c217abSAndrew Lunn #endif 447b6c217abSAndrew Lunn nvmem->eeprom.private = &nvmem->dev; 448b6c217abSAndrew Lunn nvmem->base_dev = config->base_dev; 449b6c217abSAndrew Lunn 450b6c217abSAndrew Lunn rval = device_create_bin_file(nvmem->base_dev, &nvmem->eeprom); 451b6c217abSAndrew Lunn if (rval) { 452b6c217abSAndrew Lunn dev_err(&nvmem->dev, 453b6c217abSAndrew Lunn "Failed to create eeprom binary file %d\n", rval); 454b6c217abSAndrew Lunn return rval; 455b6c217abSAndrew Lunn } 456b6c217abSAndrew Lunn 457b6c217abSAndrew Lunn nvmem->flags |= FLAG_COMPAT; 458b6c217abSAndrew Lunn 459b6c217abSAndrew Lunn return 0; 460b6c217abSAndrew Lunn } 461b6c217abSAndrew Lunn 462bee1138bSBartosz Golaszewski /** 463bee1138bSBartosz Golaszewski * nvmem_register_notifier() - Register a notifier block for nvmem events. 464bee1138bSBartosz Golaszewski * 465bee1138bSBartosz Golaszewski * @nb: notifier block to be called on nvmem events. 466bee1138bSBartosz Golaszewski * 467bee1138bSBartosz Golaszewski * Return: 0 on success, negative error number on failure. 468bee1138bSBartosz Golaszewski */ 469bee1138bSBartosz Golaszewski int nvmem_register_notifier(struct notifier_block *nb) 470bee1138bSBartosz Golaszewski { 471bee1138bSBartosz Golaszewski return blocking_notifier_chain_register(&nvmem_notifier, nb); 472bee1138bSBartosz Golaszewski } 473bee1138bSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_register_notifier); 474bee1138bSBartosz Golaszewski 475bee1138bSBartosz Golaszewski /** 476bee1138bSBartosz Golaszewski * nvmem_unregister_notifier() - Unregister a notifier block for nvmem events. 477bee1138bSBartosz Golaszewski * 478bee1138bSBartosz Golaszewski * @nb: notifier block to be unregistered. 479bee1138bSBartosz Golaszewski * 480bee1138bSBartosz Golaszewski * Return: 0 on success, negative error number on failure. 481bee1138bSBartosz Golaszewski */ 482bee1138bSBartosz Golaszewski int nvmem_unregister_notifier(struct notifier_block *nb) 483bee1138bSBartosz Golaszewski { 484bee1138bSBartosz Golaszewski return blocking_notifier_chain_unregister(&nvmem_notifier, nb); 485bee1138bSBartosz Golaszewski } 486bee1138bSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_unregister_notifier); 487bee1138bSBartosz Golaszewski 488b985f4cbSBartosz Golaszewski static int nvmem_add_cells_from_table(struct nvmem_device *nvmem) 489b985f4cbSBartosz Golaszewski { 490b985f4cbSBartosz Golaszewski const struct nvmem_cell_info *info; 491b985f4cbSBartosz Golaszewski struct nvmem_cell_table *table; 492b985f4cbSBartosz Golaszewski struct nvmem_cell *cell; 493b985f4cbSBartosz Golaszewski int rval = 0, i; 494b985f4cbSBartosz Golaszewski 495b985f4cbSBartosz Golaszewski mutex_lock(&nvmem_cell_mutex); 496b985f4cbSBartosz Golaszewski list_for_each_entry(table, &nvmem_cell_tables, node) { 497b985f4cbSBartosz Golaszewski if (strcmp(nvmem_dev_name(nvmem), table->nvmem_name) == 0) { 498b985f4cbSBartosz Golaszewski for (i = 0; i < table->ncells; i++) { 499b985f4cbSBartosz Golaszewski info = &table->cells[i]; 500b985f4cbSBartosz Golaszewski 501b985f4cbSBartosz Golaszewski cell = kzalloc(sizeof(*cell), GFP_KERNEL); 502b985f4cbSBartosz Golaszewski if (!cell) { 503b985f4cbSBartosz Golaszewski rval = -ENOMEM; 504b985f4cbSBartosz Golaszewski goto out; 505b985f4cbSBartosz Golaszewski } 506b985f4cbSBartosz Golaszewski 507b985f4cbSBartosz Golaszewski rval = nvmem_cell_info_to_nvmem_cell(nvmem, 508b985f4cbSBartosz Golaszewski info, 509b985f4cbSBartosz Golaszewski cell); 510b985f4cbSBartosz Golaszewski if (rval) { 511b985f4cbSBartosz Golaszewski kfree(cell); 512b985f4cbSBartosz Golaszewski goto out; 513b985f4cbSBartosz Golaszewski } 514b985f4cbSBartosz Golaszewski 515b985f4cbSBartosz Golaszewski nvmem_cell_add(cell); 516b985f4cbSBartosz Golaszewski } 517b985f4cbSBartosz Golaszewski } 518b985f4cbSBartosz Golaszewski } 519b985f4cbSBartosz Golaszewski 520b985f4cbSBartosz Golaszewski out: 521b985f4cbSBartosz Golaszewski mutex_unlock(&nvmem_cell_mutex); 522b985f4cbSBartosz Golaszewski return rval; 523b985f4cbSBartosz Golaszewski } 524b985f4cbSBartosz Golaszewski 525e888d445SBartosz Golaszewski static struct nvmem_cell * 526506157beSBartosz Golaszewski nvmem_find_cell_by_name(struct nvmem_device *nvmem, const char *cell_id) 527506157beSBartosz Golaszewski { 528506157beSBartosz Golaszewski struct nvmem_cell *cell = NULL; 529506157beSBartosz Golaszewski 530506157beSBartosz Golaszewski mutex_lock(&nvmem_mutex); 531506157beSBartosz Golaszewski list_for_each_entry(cell, &nvmem->cells, node) { 532506157beSBartosz Golaszewski if (strcmp(cell_id, cell->name) == 0) 533506157beSBartosz Golaszewski break; 534506157beSBartosz Golaszewski } 535506157beSBartosz Golaszewski mutex_unlock(&nvmem_mutex); 536506157beSBartosz Golaszewski 537506157beSBartosz Golaszewski return cell; 538506157beSBartosz Golaszewski } 539506157beSBartosz Golaszewski 540e888d445SBartosz Golaszewski static int nvmem_add_cells_from_of(struct nvmem_device *nvmem) 541e888d445SBartosz Golaszewski { 542e888d445SBartosz Golaszewski struct device_node *parent, *child; 543e888d445SBartosz Golaszewski struct device *dev = &nvmem->dev; 544e888d445SBartosz Golaszewski struct nvmem_cell *cell; 545e888d445SBartosz Golaszewski const __be32 *addr; 546e888d445SBartosz Golaszewski int len; 547e888d445SBartosz Golaszewski 548e888d445SBartosz Golaszewski parent = dev->of_node; 549e888d445SBartosz Golaszewski 550e888d445SBartosz Golaszewski for_each_child_of_node(parent, child) { 551e888d445SBartosz Golaszewski addr = of_get_property(child, "reg", &len); 552e888d445SBartosz Golaszewski if (!addr || (len < 2 * sizeof(u32))) { 553e888d445SBartosz Golaszewski dev_err(dev, "nvmem: invalid reg on %pOF\n", child); 554e888d445SBartosz Golaszewski return -EINVAL; 555e888d445SBartosz Golaszewski } 556e888d445SBartosz Golaszewski 557e888d445SBartosz Golaszewski cell = kzalloc(sizeof(*cell), GFP_KERNEL); 558e888d445SBartosz Golaszewski if (!cell) 559e888d445SBartosz Golaszewski return -ENOMEM; 560e888d445SBartosz Golaszewski 561e888d445SBartosz Golaszewski cell->nvmem = nvmem; 5620749aa25SSrinivas Kandagatla cell->np = of_node_get(child); 563e888d445SBartosz Golaszewski cell->offset = be32_to_cpup(addr++); 564e888d445SBartosz Golaszewski cell->bytes = be32_to_cpup(addr); 565badcdff1SRob Herring cell->name = kasprintf(GFP_KERNEL, "%pOFn", child); 566e888d445SBartosz Golaszewski 567e888d445SBartosz Golaszewski addr = of_get_property(child, "bits", &len); 568e888d445SBartosz Golaszewski if (addr && len == (2 * sizeof(u32))) { 569e888d445SBartosz Golaszewski cell->bit_offset = be32_to_cpup(addr++); 570e888d445SBartosz Golaszewski cell->nbits = be32_to_cpup(addr); 571e888d445SBartosz Golaszewski } 572e888d445SBartosz Golaszewski 573e888d445SBartosz Golaszewski if (cell->nbits) 574e888d445SBartosz Golaszewski cell->bytes = DIV_ROUND_UP( 575e888d445SBartosz Golaszewski cell->nbits + cell->bit_offset, 576e888d445SBartosz Golaszewski BITS_PER_BYTE); 577e888d445SBartosz Golaszewski 578e888d445SBartosz Golaszewski if (!IS_ALIGNED(cell->offset, nvmem->stride)) { 579e888d445SBartosz Golaszewski dev_err(dev, "cell %s unaligned to nvmem stride %d\n", 580e888d445SBartosz Golaszewski cell->name, nvmem->stride); 581e888d445SBartosz Golaszewski /* Cells already added will be freed later. */ 582badcdff1SRob Herring kfree(cell->name); 583e888d445SBartosz Golaszewski kfree(cell); 584e888d445SBartosz Golaszewski return -EINVAL; 585e888d445SBartosz Golaszewski } 586e888d445SBartosz Golaszewski 587e888d445SBartosz Golaszewski nvmem_cell_add(cell); 588e888d445SBartosz Golaszewski } 589e888d445SBartosz Golaszewski 590e888d445SBartosz Golaszewski return 0; 591e888d445SBartosz Golaszewski } 592e888d445SBartosz Golaszewski 593eace75cfSSrinivas Kandagatla /** 594eace75cfSSrinivas Kandagatla * nvmem_register() - Register a nvmem device for given nvmem_config. 595eace75cfSSrinivas Kandagatla * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem 596eace75cfSSrinivas Kandagatla * 597eace75cfSSrinivas Kandagatla * @config: nvmem device configuration with which nvmem device is created. 598eace75cfSSrinivas Kandagatla * 599eace75cfSSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device 600eace75cfSSrinivas Kandagatla * on success. 601eace75cfSSrinivas Kandagatla */ 602eace75cfSSrinivas Kandagatla 603eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem_register(const struct nvmem_config *config) 604eace75cfSSrinivas Kandagatla { 605eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem; 606eace75cfSSrinivas Kandagatla int rval; 607eace75cfSSrinivas Kandagatla 608eace75cfSSrinivas Kandagatla if (!config->dev) 609eace75cfSSrinivas Kandagatla return ERR_PTR(-EINVAL); 610eace75cfSSrinivas Kandagatla 611eace75cfSSrinivas Kandagatla nvmem = kzalloc(sizeof(*nvmem), GFP_KERNEL); 612eace75cfSSrinivas Kandagatla if (!nvmem) 613eace75cfSSrinivas Kandagatla return ERR_PTR(-ENOMEM); 614eace75cfSSrinivas Kandagatla 615eace75cfSSrinivas Kandagatla rval = ida_simple_get(&nvmem_ida, 0, 0, GFP_KERNEL); 616eace75cfSSrinivas Kandagatla if (rval < 0) { 617eace75cfSSrinivas Kandagatla kfree(nvmem); 618eace75cfSSrinivas Kandagatla return ERR_PTR(rval); 619eace75cfSSrinivas Kandagatla } 620eace75cfSSrinivas Kandagatla 621c1de7f43SBartosz Golaszewski kref_init(&nvmem->refcnt); 622c7235ee3SBartosz Golaszewski INIT_LIST_HEAD(&nvmem->cells); 623c1de7f43SBartosz Golaszewski 624eace75cfSSrinivas Kandagatla nvmem->id = rval; 625eace75cfSSrinivas Kandagatla nvmem->owner = config->owner; 62617eb18d6SMasahiro Yamada if (!nvmem->owner && config->dev->driver) 62717eb18d6SMasahiro Yamada nvmem->owner = config->dev->driver->owner; 62899897efdSHeiner Kallweit nvmem->stride = config->stride ?: 1; 62999897efdSHeiner Kallweit nvmem->word_size = config->word_size ?: 1; 630795ddd18SSrinivas Kandagatla nvmem->size = config->size; 631eace75cfSSrinivas Kandagatla nvmem->dev.type = &nvmem_provider_type; 632eace75cfSSrinivas Kandagatla nvmem->dev.bus = &nvmem_bus_type; 633eace75cfSSrinivas Kandagatla nvmem->dev.parent = config->dev; 634795ddd18SSrinivas Kandagatla nvmem->priv = config->priv; 63516688453SAlexandre Belloni nvmem->type = config->type; 636795ddd18SSrinivas Kandagatla nvmem->reg_read = config->reg_read; 637795ddd18SSrinivas Kandagatla nvmem->reg_write = config->reg_write; 638fc2f9970SHeiner Kallweit nvmem->dev.of_node = config->dev->of_node; 639fd0f4906SAndrey Smirnov 640fd0f4906SAndrey Smirnov if (config->id == -1 && config->name) { 641fd0f4906SAndrey Smirnov dev_set_name(&nvmem->dev, "%s", config->name); 642fd0f4906SAndrey Smirnov } else { 643eace75cfSSrinivas Kandagatla dev_set_name(&nvmem->dev, "%s%d", 6445253193dSAban Bedel config->name ? : "nvmem", 6455253193dSAban Bedel config->name ? config->id : nvmem->id); 646fd0f4906SAndrey Smirnov } 647eace75cfSSrinivas Kandagatla 648fc2f9970SHeiner Kallweit nvmem->read_only = device_property_present(config->dev, "read-only") | 649eace75cfSSrinivas Kandagatla config->read_only; 650eace75cfSSrinivas Kandagatla 651811b0d65SAndrew Lunn if (config->root_only) 652811b0d65SAndrew Lunn nvmem->dev.groups = nvmem->read_only ? 653811b0d65SAndrew Lunn nvmem_ro_root_dev_groups : 654811b0d65SAndrew Lunn nvmem_rw_root_dev_groups; 655811b0d65SAndrew Lunn else 656811b0d65SAndrew Lunn nvmem->dev.groups = nvmem->read_only ? 657811b0d65SAndrew Lunn nvmem_ro_dev_groups : 658eace75cfSSrinivas Kandagatla nvmem_rw_dev_groups; 659eace75cfSSrinivas Kandagatla 660eace75cfSSrinivas Kandagatla device_initialize(&nvmem->dev); 661eace75cfSSrinivas Kandagatla 662eace75cfSSrinivas Kandagatla dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name); 663eace75cfSSrinivas Kandagatla 664eace75cfSSrinivas Kandagatla rval = device_add(&nvmem->dev); 665b6c217abSAndrew Lunn if (rval) 6663360acdfSJohan Hovold goto err_put_device; 667b6c217abSAndrew Lunn 668b6c217abSAndrew Lunn if (config->compat) { 669b6c217abSAndrew Lunn rval = nvmem_setup_compat(nvmem, config); 670b6c217abSAndrew Lunn if (rval) 6713360acdfSJohan Hovold goto err_device_del; 672eace75cfSSrinivas Kandagatla } 673eace75cfSSrinivas Kandagatla 674fa72d847SBartosz Golaszewski if (config->cells) { 675fa72d847SBartosz Golaszewski rval = nvmem_add_cells(nvmem, config->cells, config->ncells); 676fa72d847SBartosz Golaszewski if (rval) 677fa72d847SBartosz Golaszewski goto err_teardown_compat; 678fa72d847SBartosz Golaszewski } 679eace75cfSSrinivas Kandagatla 680b985f4cbSBartosz Golaszewski rval = nvmem_add_cells_from_table(nvmem); 681b985f4cbSBartosz Golaszewski if (rval) 682b985f4cbSBartosz Golaszewski goto err_remove_cells; 683b985f4cbSBartosz Golaszewski 684e888d445SBartosz Golaszewski rval = nvmem_add_cells_from_of(nvmem); 685e888d445SBartosz Golaszewski if (rval) 686e888d445SBartosz Golaszewski goto err_remove_cells; 687e888d445SBartosz Golaszewski 688bee1138bSBartosz Golaszewski rval = blocking_notifier_call_chain(&nvmem_notifier, NVMEM_ADD, nvmem); 689bee1138bSBartosz Golaszewski if (rval) 690bee1138bSBartosz Golaszewski goto err_remove_cells; 691bee1138bSBartosz Golaszewski 692eace75cfSSrinivas Kandagatla return nvmem; 6933360acdfSJohan Hovold 694b985f4cbSBartosz Golaszewski err_remove_cells: 695b985f4cbSBartosz Golaszewski nvmem_device_remove_all_cells(nvmem); 696fa72d847SBartosz Golaszewski err_teardown_compat: 697fa72d847SBartosz Golaszewski if (config->compat) 698fa72d847SBartosz Golaszewski device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); 6993360acdfSJohan Hovold err_device_del: 7003360acdfSJohan Hovold device_del(&nvmem->dev); 7013360acdfSJohan Hovold err_put_device: 7023360acdfSJohan Hovold put_device(&nvmem->dev); 7033360acdfSJohan Hovold 704b6c217abSAndrew Lunn return ERR_PTR(rval); 705eace75cfSSrinivas Kandagatla } 706eace75cfSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_register); 707eace75cfSSrinivas Kandagatla 708c1de7f43SBartosz Golaszewski static void nvmem_device_release(struct kref *kref) 709c1de7f43SBartosz Golaszewski { 710c1de7f43SBartosz Golaszewski struct nvmem_device *nvmem; 711c1de7f43SBartosz Golaszewski 712c1de7f43SBartosz Golaszewski nvmem = container_of(kref, struct nvmem_device, refcnt); 713c1de7f43SBartosz Golaszewski 714bee1138bSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_REMOVE, nvmem); 715bee1138bSBartosz Golaszewski 716c1de7f43SBartosz Golaszewski if (nvmem->flags & FLAG_COMPAT) 717c1de7f43SBartosz Golaszewski device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); 718c1de7f43SBartosz Golaszewski 719c1de7f43SBartosz Golaszewski nvmem_device_remove_all_cells(nvmem); 720c1de7f43SBartosz Golaszewski device_del(&nvmem->dev); 721c1de7f43SBartosz Golaszewski put_device(&nvmem->dev); 722c1de7f43SBartosz Golaszewski } 723c1de7f43SBartosz Golaszewski 724eace75cfSSrinivas Kandagatla /** 725eace75cfSSrinivas Kandagatla * nvmem_unregister() - Unregister previously registered nvmem device 726eace75cfSSrinivas Kandagatla * 727eace75cfSSrinivas Kandagatla * @nvmem: Pointer to previously registered nvmem device. 728eace75cfSSrinivas Kandagatla */ 729bf58e882SBartosz Golaszewski void nvmem_unregister(struct nvmem_device *nvmem) 730eace75cfSSrinivas Kandagatla { 731c1de7f43SBartosz Golaszewski kref_put(&nvmem->refcnt, nvmem_device_release); 732eace75cfSSrinivas Kandagatla } 733eace75cfSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_unregister); 734eace75cfSSrinivas Kandagatla 735f1f50ecaSAndrey Smirnov static void devm_nvmem_release(struct device *dev, void *res) 736f1f50ecaSAndrey Smirnov { 737bf58e882SBartosz Golaszewski nvmem_unregister(*(struct nvmem_device **)res); 738f1f50ecaSAndrey Smirnov } 739f1f50ecaSAndrey Smirnov 740f1f50ecaSAndrey Smirnov /** 741f1f50ecaSAndrey Smirnov * devm_nvmem_register() - Register a managed nvmem device for given 742f1f50ecaSAndrey Smirnov * nvmem_config. 743f1f50ecaSAndrey Smirnov * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem 744f1f50ecaSAndrey Smirnov * 745b378c779SSrinivas Kandagatla * @dev: Device that uses the nvmem device. 746f1f50ecaSAndrey Smirnov * @config: nvmem device configuration with which nvmem device is created. 747f1f50ecaSAndrey Smirnov * 748f1f50ecaSAndrey Smirnov * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device 749f1f50ecaSAndrey Smirnov * on success. 750f1f50ecaSAndrey Smirnov */ 751f1f50ecaSAndrey Smirnov struct nvmem_device *devm_nvmem_register(struct device *dev, 752f1f50ecaSAndrey Smirnov const struct nvmem_config *config) 753f1f50ecaSAndrey Smirnov { 754f1f50ecaSAndrey Smirnov struct nvmem_device **ptr, *nvmem; 755f1f50ecaSAndrey Smirnov 756f1f50ecaSAndrey Smirnov ptr = devres_alloc(devm_nvmem_release, sizeof(*ptr), GFP_KERNEL); 757f1f50ecaSAndrey Smirnov if (!ptr) 758f1f50ecaSAndrey Smirnov return ERR_PTR(-ENOMEM); 759f1f50ecaSAndrey Smirnov 760f1f50ecaSAndrey Smirnov nvmem = nvmem_register(config); 761f1f50ecaSAndrey Smirnov 762f1f50ecaSAndrey Smirnov if (!IS_ERR(nvmem)) { 763f1f50ecaSAndrey Smirnov *ptr = nvmem; 764f1f50ecaSAndrey Smirnov devres_add(dev, ptr); 765f1f50ecaSAndrey Smirnov } else { 766f1f50ecaSAndrey Smirnov devres_free(ptr); 767f1f50ecaSAndrey Smirnov } 768f1f50ecaSAndrey Smirnov 769f1f50ecaSAndrey Smirnov return nvmem; 770f1f50ecaSAndrey Smirnov } 771f1f50ecaSAndrey Smirnov EXPORT_SYMBOL_GPL(devm_nvmem_register); 772f1f50ecaSAndrey Smirnov 773f1f50ecaSAndrey Smirnov static int devm_nvmem_match(struct device *dev, void *res, void *data) 774f1f50ecaSAndrey Smirnov { 775f1f50ecaSAndrey Smirnov struct nvmem_device **r = res; 776f1f50ecaSAndrey Smirnov 777f1f50ecaSAndrey Smirnov return *r == data; 778f1f50ecaSAndrey Smirnov } 779f1f50ecaSAndrey Smirnov 780f1f50ecaSAndrey Smirnov /** 781f1f50ecaSAndrey Smirnov * devm_nvmem_unregister() - Unregister previously registered managed nvmem 782f1f50ecaSAndrey Smirnov * device. 783f1f50ecaSAndrey Smirnov * 784b378c779SSrinivas Kandagatla * @dev: Device that uses the nvmem device. 785f1f50ecaSAndrey Smirnov * @nvmem: Pointer to previously registered nvmem device. 786f1f50ecaSAndrey Smirnov * 787f1f50ecaSAndrey Smirnov * Return: Will be an negative on error or a zero on success. 788f1f50ecaSAndrey Smirnov */ 789f1f50ecaSAndrey Smirnov int devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem) 790f1f50ecaSAndrey Smirnov { 791f1f50ecaSAndrey Smirnov return devres_release(dev, devm_nvmem_release, devm_nvmem_match, nvmem); 792f1f50ecaSAndrey Smirnov } 793f1f50ecaSAndrey Smirnov EXPORT_SYMBOL(devm_nvmem_unregister); 794f1f50ecaSAndrey Smirnov 79569aba794SSrinivas Kandagatla static struct nvmem_device *__nvmem_device_get(struct device_node *np, 796506157beSBartosz Golaszewski const char *nvmem_name) 79769aba794SSrinivas Kandagatla { 79869aba794SSrinivas Kandagatla struct nvmem_device *nvmem = NULL; 79969aba794SSrinivas Kandagatla 800c7235ee3SBartosz Golaszewski mutex_lock(&nvmem_mutex); 801506157beSBartosz Golaszewski nvmem = np ? of_nvmem_find(np) : nvmem_find(nvmem_name); 80269aba794SSrinivas Kandagatla mutex_unlock(&nvmem_mutex); 803c7235ee3SBartosz Golaszewski if (!nvmem) 804c7235ee3SBartosz Golaszewski return ERR_PTR(-EPROBE_DEFER); 80569aba794SSrinivas Kandagatla 80669aba794SSrinivas Kandagatla if (!try_module_get(nvmem->owner)) { 80769aba794SSrinivas Kandagatla dev_err(&nvmem->dev, 80869aba794SSrinivas Kandagatla "could not increase module refcount for cell %s\n", 8095db652c9SBartosz Golaszewski nvmem_dev_name(nvmem)); 81069aba794SSrinivas Kandagatla 81169aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 81269aba794SSrinivas Kandagatla } 81369aba794SSrinivas Kandagatla 814c1de7f43SBartosz Golaszewski kref_get(&nvmem->refcnt); 815c1de7f43SBartosz Golaszewski 81669aba794SSrinivas Kandagatla return nvmem; 81769aba794SSrinivas Kandagatla } 81869aba794SSrinivas Kandagatla 81969aba794SSrinivas Kandagatla static void __nvmem_device_put(struct nvmem_device *nvmem) 82069aba794SSrinivas Kandagatla { 82169aba794SSrinivas Kandagatla module_put(nvmem->owner); 822c1de7f43SBartosz Golaszewski kref_put(&nvmem->refcnt, nvmem_device_release); 82369aba794SSrinivas Kandagatla } 82469aba794SSrinivas Kandagatla 825e701c67cSMasahiro Yamada #if IS_ENABLED(CONFIG_OF) 826e2a5402eSSrinivas Kandagatla /** 827e2a5402eSSrinivas Kandagatla * of_nvmem_device_get() - Get nvmem device from a given id 828e2a5402eSSrinivas Kandagatla * 82929143268SVivek Gautam * @np: Device tree node that uses the nvmem device. 830e2a5402eSSrinivas Kandagatla * @id: nvmem name from nvmem-names property. 831e2a5402eSSrinivas Kandagatla * 832e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device 833e2a5402eSSrinivas Kandagatla * on success. 834e2a5402eSSrinivas Kandagatla */ 835e2a5402eSSrinivas Kandagatla struct nvmem_device *of_nvmem_device_get(struct device_node *np, const char *id) 836e2a5402eSSrinivas Kandagatla { 837e2a5402eSSrinivas Kandagatla 838e2a5402eSSrinivas Kandagatla struct device_node *nvmem_np; 839e2a5402eSSrinivas Kandagatla int index; 840e2a5402eSSrinivas Kandagatla 841e2a5402eSSrinivas Kandagatla index = of_property_match_string(np, "nvmem-names", id); 842e2a5402eSSrinivas Kandagatla 843e2a5402eSSrinivas Kandagatla nvmem_np = of_parse_phandle(np, "nvmem", index); 844e2a5402eSSrinivas Kandagatla if (!nvmem_np) 845e2a5402eSSrinivas Kandagatla return ERR_PTR(-EINVAL); 846e2a5402eSSrinivas Kandagatla 847506157beSBartosz Golaszewski return __nvmem_device_get(nvmem_np, NULL); 848e2a5402eSSrinivas Kandagatla } 849e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_nvmem_device_get); 850e2a5402eSSrinivas Kandagatla #endif 851e2a5402eSSrinivas Kandagatla 852e2a5402eSSrinivas Kandagatla /** 853e2a5402eSSrinivas Kandagatla * nvmem_device_get() - Get nvmem device from a given id 854e2a5402eSSrinivas Kandagatla * 85529143268SVivek Gautam * @dev: Device that uses the nvmem device. 85629143268SVivek Gautam * @dev_name: name of the requested nvmem device. 857e2a5402eSSrinivas Kandagatla * 858e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device 859e2a5402eSSrinivas Kandagatla * on success. 860e2a5402eSSrinivas Kandagatla */ 861e2a5402eSSrinivas Kandagatla struct nvmem_device *nvmem_device_get(struct device *dev, const char *dev_name) 862e2a5402eSSrinivas Kandagatla { 863e2a5402eSSrinivas Kandagatla if (dev->of_node) { /* try dt first */ 864e2a5402eSSrinivas Kandagatla struct nvmem_device *nvmem; 865e2a5402eSSrinivas Kandagatla 866e2a5402eSSrinivas Kandagatla nvmem = of_nvmem_device_get(dev->of_node, dev_name); 867e2a5402eSSrinivas Kandagatla 868e2a5402eSSrinivas Kandagatla if (!IS_ERR(nvmem) || PTR_ERR(nvmem) == -EPROBE_DEFER) 869e2a5402eSSrinivas Kandagatla return nvmem; 870e2a5402eSSrinivas Kandagatla 871e2a5402eSSrinivas Kandagatla } 872e2a5402eSSrinivas Kandagatla 873e2a5402eSSrinivas Kandagatla return nvmem_find(dev_name); 874e2a5402eSSrinivas Kandagatla } 875e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_get); 876e2a5402eSSrinivas Kandagatla 877e2a5402eSSrinivas Kandagatla static int devm_nvmem_device_match(struct device *dev, void *res, void *data) 878e2a5402eSSrinivas Kandagatla { 879e2a5402eSSrinivas Kandagatla struct nvmem_device **nvmem = res; 880e2a5402eSSrinivas Kandagatla 881e2a5402eSSrinivas Kandagatla if (WARN_ON(!nvmem || !*nvmem)) 882e2a5402eSSrinivas Kandagatla return 0; 883e2a5402eSSrinivas Kandagatla 884e2a5402eSSrinivas Kandagatla return *nvmem == data; 885e2a5402eSSrinivas Kandagatla } 886e2a5402eSSrinivas Kandagatla 887e2a5402eSSrinivas Kandagatla static void devm_nvmem_device_release(struct device *dev, void *res) 888e2a5402eSSrinivas Kandagatla { 889e2a5402eSSrinivas Kandagatla nvmem_device_put(*(struct nvmem_device **)res); 890e2a5402eSSrinivas Kandagatla } 891e2a5402eSSrinivas Kandagatla 892e2a5402eSSrinivas Kandagatla /** 893e2a5402eSSrinivas Kandagatla * devm_nvmem_device_put() - put alredy got nvmem device 894e2a5402eSSrinivas Kandagatla * 89529143268SVivek Gautam * @dev: Device that uses the nvmem device. 896e2a5402eSSrinivas Kandagatla * @nvmem: pointer to nvmem device allocated by devm_nvmem_cell_get(), 897e2a5402eSSrinivas Kandagatla * that needs to be released. 898e2a5402eSSrinivas Kandagatla */ 899e2a5402eSSrinivas Kandagatla void devm_nvmem_device_put(struct device *dev, struct nvmem_device *nvmem) 900e2a5402eSSrinivas Kandagatla { 901e2a5402eSSrinivas Kandagatla int ret; 902e2a5402eSSrinivas Kandagatla 903e2a5402eSSrinivas Kandagatla ret = devres_release(dev, devm_nvmem_device_release, 904e2a5402eSSrinivas Kandagatla devm_nvmem_device_match, nvmem); 905e2a5402eSSrinivas Kandagatla 906e2a5402eSSrinivas Kandagatla WARN_ON(ret); 907e2a5402eSSrinivas Kandagatla } 908e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_device_put); 909e2a5402eSSrinivas Kandagatla 910e2a5402eSSrinivas Kandagatla /** 911e2a5402eSSrinivas Kandagatla * nvmem_device_put() - put alredy got nvmem device 912e2a5402eSSrinivas Kandagatla * 913e2a5402eSSrinivas Kandagatla * @nvmem: pointer to nvmem device that needs to be released. 914e2a5402eSSrinivas Kandagatla */ 915e2a5402eSSrinivas Kandagatla void nvmem_device_put(struct nvmem_device *nvmem) 916e2a5402eSSrinivas Kandagatla { 917e2a5402eSSrinivas Kandagatla __nvmem_device_put(nvmem); 918e2a5402eSSrinivas Kandagatla } 919e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_put); 920e2a5402eSSrinivas Kandagatla 921e2a5402eSSrinivas Kandagatla /** 922e2a5402eSSrinivas Kandagatla * devm_nvmem_device_get() - Get nvmem cell of device form a given id 923e2a5402eSSrinivas Kandagatla * 92429143268SVivek Gautam * @dev: Device that requests the nvmem device. 92529143268SVivek Gautam * @id: name id for the requested nvmem device. 926e2a5402eSSrinivas Kandagatla * 927e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_cell 928e2a5402eSSrinivas Kandagatla * on success. The nvmem_cell will be freed by the automatically once the 929e2a5402eSSrinivas Kandagatla * device is freed. 930e2a5402eSSrinivas Kandagatla */ 931e2a5402eSSrinivas Kandagatla struct nvmem_device *devm_nvmem_device_get(struct device *dev, const char *id) 932e2a5402eSSrinivas Kandagatla { 933e2a5402eSSrinivas Kandagatla struct nvmem_device **ptr, *nvmem; 934e2a5402eSSrinivas Kandagatla 935e2a5402eSSrinivas Kandagatla ptr = devres_alloc(devm_nvmem_device_release, sizeof(*ptr), GFP_KERNEL); 936e2a5402eSSrinivas Kandagatla if (!ptr) 937e2a5402eSSrinivas Kandagatla return ERR_PTR(-ENOMEM); 938e2a5402eSSrinivas Kandagatla 939e2a5402eSSrinivas Kandagatla nvmem = nvmem_device_get(dev, id); 940e2a5402eSSrinivas Kandagatla if (!IS_ERR(nvmem)) { 941e2a5402eSSrinivas Kandagatla *ptr = nvmem; 942e2a5402eSSrinivas Kandagatla devres_add(dev, ptr); 943e2a5402eSSrinivas Kandagatla } else { 944e2a5402eSSrinivas Kandagatla devres_free(ptr); 945e2a5402eSSrinivas Kandagatla } 946e2a5402eSSrinivas Kandagatla 947e2a5402eSSrinivas Kandagatla return nvmem; 948e2a5402eSSrinivas Kandagatla } 949e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_device_get); 950e2a5402eSSrinivas Kandagatla 951506157beSBartosz Golaszewski static struct nvmem_cell * 952506157beSBartosz Golaszewski nvmem_cell_get_from_lookup(struct device *dev, const char *con_id) 95369aba794SSrinivas Kandagatla { 954506157beSBartosz Golaszewski struct nvmem_cell *cell = ERR_PTR(-ENOENT); 955506157beSBartosz Golaszewski struct nvmem_cell_lookup *lookup; 95669aba794SSrinivas Kandagatla struct nvmem_device *nvmem; 957506157beSBartosz Golaszewski const char *dev_id; 95869aba794SSrinivas Kandagatla 959506157beSBartosz Golaszewski if (!dev) 960506157beSBartosz Golaszewski return ERR_PTR(-EINVAL); 96169aba794SSrinivas Kandagatla 962506157beSBartosz Golaszewski dev_id = dev_name(dev); 963506157beSBartosz Golaszewski 964506157beSBartosz Golaszewski mutex_lock(&nvmem_lookup_mutex); 965506157beSBartosz Golaszewski 966506157beSBartosz Golaszewski list_for_each_entry(lookup, &nvmem_lookup_list, node) { 967506157beSBartosz Golaszewski if ((strcmp(lookup->dev_id, dev_id) == 0) && 968506157beSBartosz Golaszewski (strcmp(lookup->con_id, con_id) == 0)) { 969506157beSBartosz Golaszewski /* This is the right entry. */ 970506157beSBartosz Golaszewski nvmem = __nvmem_device_get(NULL, lookup->nvmem_name); 971cccb3b19SBartosz Golaszewski if (IS_ERR(nvmem)) { 972506157beSBartosz Golaszewski /* Provider may not be registered yet. */ 973cccb3b19SBartosz Golaszewski cell = ERR_CAST(nvmem); 974506157beSBartosz Golaszewski goto out; 975506157beSBartosz Golaszewski } 976506157beSBartosz Golaszewski 977506157beSBartosz Golaszewski cell = nvmem_find_cell_by_name(nvmem, 978506157beSBartosz Golaszewski lookup->cell_name); 979506157beSBartosz Golaszewski if (!cell) { 980506157beSBartosz Golaszewski __nvmem_device_put(nvmem); 981cccb3b19SBartosz Golaszewski cell = ERR_PTR(-ENOENT); 982506157beSBartosz Golaszewski goto out; 983506157beSBartosz Golaszewski } 984506157beSBartosz Golaszewski } 985506157beSBartosz Golaszewski } 986506157beSBartosz Golaszewski 987506157beSBartosz Golaszewski out: 988506157beSBartosz Golaszewski mutex_unlock(&nvmem_lookup_mutex); 98969aba794SSrinivas Kandagatla return cell; 99069aba794SSrinivas Kandagatla } 99169aba794SSrinivas Kandagatla 992e701c67cSMasahiro Yamada #if IS_ENABLED(CONFIG_OF) 9933c53e235SArnd Bergmann static struct nvmem_cell * 9940749aa25SSrinivas Kandagatla nvmem_find_cell_by_node(struct nvmem_device *nvmem, struct device_node *np) 9953c53e235SArnd Bergmann { 9963c53e235SArnd Bergmann struct nvmem_cell *cell = NULL; 9973c53e235SArnd Bergmann 9983c53e235SArnd Bergmann mutex_lock(&nvmem_mutex); 9993c53e235SArnd Bergmann list_for_each_entry(cell, &nvmem->cells, node) { 10000749aa25SSrinivas Kandagatla if (np == cell->np) 10013c53e235SArnd Bergmann break; 10023c53e235SArnd Bergmann } 10033c53e235SArnd Bergmann mutex_unlock(&nvmem_mutex); 10043c53e235SArnd Bergmann 10053c53e235SArnd Bergmann return cell; 10063c53e235SArnd Bergmann } 10073c53e235SArnd Bergmann 100869aba794SSrinivas Kandagatla /** 100969aba794SSrinivas Kandagatla * of_nvmem_cell_get() - Get a nvmem cell from given device node and cell id 101069aba794SSrinivas Kandagatla * 101129143268SVivek Gautam * @np: Device tree node that uses the nvmem cell. 1012165589f0SBartosz Golaszewski * @id: nvmem cell name from nvmem-cell-names property, or NULL 1013fd0c478cSVivek Gautam * for the cell at index 0 (the lone cell with no accompanying 1014fd0c478cSVivek Gautam * nvmem-cell-names property). 101569aba794SSrinivas Kandagatla * 101669aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 101769aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 101869aba794SSrinivas Kandagatla * nvmem_cell_put(). 101969aba794SSrinivas Kandagatla */ 1020165589f0SBartosz Golaszewski struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *id) 102169aba794SSrinivas Kandagatla { 102269aba794SSrinivas Kandagatla struct device_node *cell_np, *nvmem_np; 102369aba794SSrinivas Kandagatla struct nvmem_device *nvmem; 1024e888d445SBartosz Golaszewski struct nvmem_cell *cell; 1025fd0c478cSVivek Gautam int index = 0; 102669aba794SSrinivas Kandagatla 1027fd0c478cSVivek Gautam /* if cell name exists, find index to the name */ 1028165589f0SBartosz Golaszewski if (id) 1029165589f0SBartosz Golaszewski index = of_property_match_string(np, "nvmem-cell-names", id); 103069aba794SSrinivas Kandagatla 103169aba794SSrinivas Kandagatla cell_np = of_parse_phandle(np, "nvmem-cells", index); 103269aba794SSrinivas Kandagatla if (!cell_np) 103369aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 103469aba794SSrinivas Kandagatla 103569aba794SSrinivas Kandagatla nvmem_np = of_get_next_parent(cell_np); 103669aba794SSrinivas Kandagatla if (!nvmem_np) 103769aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 103869aba794SSrinivas Kandagatla 1039506157beSBartosz Golaszewski nvmem = __nvmem_device_get(nvmem_np, NULL); 1040aad8d097SMasahiro Yamada of_node_put(nvmem_np); 104169aba794SSrinivas Kandagatla if (IS_ERR(nvmem)) 104269aba794SSrinivas Kandagatla return ERR_CAST(nvmem); 104369aba794SSrinivas Kandagatla 10440749aa25SSrinivas Kandagatla cell = nvmem_find_cell_by_node(nvmem, cell_np); 104569aba794SSrinivas Kandagatla if (!cell) { 1046e888d445SBartosz Golaszewski __nvmem_device_put(nvmem); 1047e888d445SBartosz Golaszewski return ERR_PTR(-ENOENT); 104869aba794SSrinivas Kandagatla } 104969aba794SSrinivas Kandagatla 105069aba794SSrinivas Kandagatla return cell; 105169aba794SSrinivas Kandagatla } 105269aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_nvmem_cell_get); 105369aba794SSrinivas Kandagatla #endif 105469aba794SSrinivas Kandagatla 105569aba794SSrinivas Kandagatla /** 105669aba794SSrinivas Kandagatla * nvmem_cell_get() - Get nvmem cell of device form a given cell name 105769aba794SSrinivas Kandagatla * 105829143268SVivek Gautam * @dev: Device that requests the nvmem cell. 1059165589f0SBartosz Golaszewski * @id: nvmem cell name to get (this corresponds with the name from the 1060165589f0SBartosz Golaszewski * nvmem-cell-names property for DT systems and with the con_id from 1061165589f0SBartosz Golaszewski * the lookup entry for non-DT systems). 106269aba794SSrinivas Kandagatla * 106369aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 106469aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 106569aba794SSrinivas Kandagatla * nvmem_cell_put(). 106669aba794SSrinivas Kandagatla */ 1067165589f0SBartosz Golaszewski struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *id) 106869aba794SSrinivas Kandagatla { 106969aba794SSrinivas Kandagatla struct nvmem_cell *cell; 107069aba794SSrinivas Kandagatla 107169aba794SSrinivas Kandagatla if (dev->of_node) { /* try dt first */ 1072165589f0SBartosz Golaszewski cell = of_nvmem_cell_get(dev->of_node, id); 107369aba794SSrinivas Kandagatla if (!IS_ERR(cell) || PTR_ERR(cell) == -EPROBE_DEFER) 107469aba794SSrinivas Kandagatla return cell; 107569aba794SSrinivas Kandagatla } 107669aba794SSrinivas Kandagatla 1077165589f0SBartosz Golaszewski /* NULL cell id only allowed for device tree; invalid otherwise */ 1078165589f0SBartosz Golaszewski if (!id) 107987ed1405SDouglas Anderson return ERR_PTR(-EINVAL); 108087ed1405SDouglas Anderson 1081165589f0SBartosz Golaszewski return nvmem_cell_get_from_lookup(dev, id); 108269aba794SSrinivas Kandagatla } 108369aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_get); 108469aba794SSrinivas Kandagatla 108569aba794SSrinivas Kandagatla static void devm_nvmem_cell_release(struct device *dev, void *res) 108669aba794SSrinivas Kandagatla { 108769aba794SSrinivas Kandagatla nvmem_cell_put(*(struct nvmem_cell **)res); 108869aba794SSrinivas Kandagatla } 108969aba794SSrinivas Kandagatla 109069aba794SSrinivas Kandagatla /** 109169aba794SSrinivas Kandagatla * devm_nvmem_cell_get() - Get nvmem cell of device form a given id 109269aba794SSrinivas Kandagatla * 109329143268SVivek Gautam * @dev: Device that requests the nvmem cell. 109429143268SVivek Gautam * @id: nvmem cell name id to get. 109569aba794SSrinivas Kandagatla * 109669aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 109769aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 109869aba794SSrinivas Kandagatla * automatically once the device is freed. 109969aba794SSrinivas Kandagatla */ 110069aba794SSrinivas Kandagatla struct nvmem_cell *devm_nvmem_cell_get(struct device *dev, const char *id) 110169aba794SSrinivas Kandagatla { 110269aba794SSrinivas Kandagatla struct nvmem_cell **ptr, *cell; 110369aba794SSrinivas Kandagatla 110469aba794SSrinivas Kandagatla ptr = devres_alloc(devm_nvmem_cell_release, sizeof(*ptr), GFP_KERNEL); 110569aba794SSrinivas Kandagatla if (!ptr) 110669aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 110769aba794SSrinivas Kandagatla 110869aba794SSrinivas Kandagatla cell = nvmem_cell_get(dev, id); 110969aba794SSrinivas Kandagatla if (!IS_ERR(cell)) { 111069aba794SSrinivas Kandagatla *ptr = cell; 111169aba794SSrinivas Kandagatla devres_add(dev, ptr); 111269aba794SSrinivas Kandagatla } else { 111369aba794SSrinivas Kandagatla devres_free(ptr); 111469aba794SSrinivas Kandagatla } 111569aba794SSrinivas Kandagatla 111669aba794SSrinivas Kandagatla return cell; 111769aba794SSrinivas Kandagatla } 111869aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_cell_get); 111969aba794SSrinivas Kandagatla 112069aba794SSrinivas Kandagatla static int devm_nvmem_cell_match(struct device *dev, void *res, void *data) 112169aba794SSrinivas Kandagatla { 112269aba794SSrinivas Kandagatla struct nvmem_cell **c = res; 112369aba794SSrinivas Kandagatla 112469aba794SSrinivas Kandagatla if (WARN_ON(!c || !*c)) 112569aba794SSrinivas Kandagatla return 0; 112669aba794SSrinivas Kandagatla 112769aba794SSrinivas Kandagatla return *c == data; 112869aba794SSrinivas Kandagatla } 112969aba794SSrinivas Kandagatla 113069aba794SSrinivas Kandagatla /** 113169aba794SSrinivas Kandagatla * devm_nvmem_cell_put() - Release previously allocated nvmem cell 113269aba794SSrinivas Kandagatla * from devm_nvmem_cell_get. 113369aba794SSrinivas Kandagatla * 113429143268SVivek Gautam * @dev: Device that requests the nvmem cell. 113529143268SVivek Gautam * @cell: Previously allocated nvmem cell by devm_nvmem_cell_get(). 113669aba794SSrinivas Kandagatla */ 113769aba794SSrinivas Kandagatla void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell) 113869aba794SSrinivas Kandagatla { 113969aba794SSrinivas Kandagatla int ret; 114069aba794SSrinivas Kandagatla 114169aba794SSrinivas Kandagatla ret = devres_release(dev, devm_nvmem_cell_release, 114269aba794SSrinivas Kandagatla devm_nvmem_cell_match, cell); 114369aba794SSrinivas Kandagatla 114469aba794SSrinivas Kandagatla WARN_ON(ret); 114569aba794SSrinivas Kandagatla } 114669aba794SSrinivas Kandagatla EXPORT_SYMBOL(devm_nvmem_cell_put); 114769aba794SSrinivas Kandagatla 114869aba794SSrinivas Kandagatla /** 114969aba794SSrinivas Kandagatla * nvmem_cell_put() - Release previously allocated nvmem cell. 115069aba794SSrinivas Kandagatla * 115129143268SVivek Gautam * @cell: Previously allocated nvmem cell by nvmem_cell_get(). 115269aba794SSrinivas Kandagatla */ 115369aba794SSrinivas Kandagatla void nvmem_cell_put(struct nvmem_cell *cell) 115469aba794SSrinivas Kandagatla { 115569aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 115669aba794SSrinivas Kandagatla 115769aba794SSrinivas Kandagatla __nvmem_device_put(nvmem); 115869aba794SSrinivas Kandagatla } 115969aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_put); 116069aba794SSrinivas Kandagatla 1161f7c04f16SMasahiro Yamada static void nvmem_shift_read_buffer_in_place(struct nvmem_cell *cell, void *buf) 116269aba794SSrinivas Kandagatla { 116369aba794SSrinivas Kandagatla u8 *p, *b; 116469aba794SSrinivas Kandagatla int i, bit_offset = cell->bit_offset; 116569aba794SSrinivas Kandagatla 116669aba794SSrinivas Kandagatla p = b = buf; 116769aba794SSrinivas Kandagatla if (bit_offset) { 116869aba794SSrinivas Kandagatla /* First shift */ 116969aba794SSrinivas Kandagatla *b++ >>= bit_offset; 117069aba794SSrinivas Kandagatla 117169aba794SSrinivas Kandagatla /* setup rest of the bytes if any */ 117269aba794SSrinivas Kandagatla for (i = 1; i < cell->bytes; i++) { 117369aba794SSrinivas Kandagatla /* Get bits from next byte and shift them towards msb */ 117469aba794SSrinivas Kandagatla *p |= *b << (BITS_PER_BYTE - bit_offset); 117569aba794SSrinivas Kandagatla 117669aba794SSrinivas Kandagatla p = b; 117769aba794SSrinivas Kandagatla *b++ >>= bit_offset; 117869aba794SSrinivas Kandagatla } 117969aba794SSrinivas Kandagatla 118069aba794SSrinivas Kandagatla /* result fits in less bytes */ 118169aba794SSrinivas Kandagatla if (cell->bytes != DIV_ROUND_UP(cell->nbits, BITS_PER_BYTE)) 118269aba794SSrinivas Kandagatla *p-- = 0; 118369aba794SSrinivas Kandagatla } 118469aba794SSrinivas Kandagatla /* clear msb bits if any leftover in the last byte */ 118569aba794SSrinivas Kandagatla *p &= GENMASK((cell->nbits%BITS_PER_BYTE) - 1, 0); 118669aba794SSrinivas Kandagatla } 118769aba794SSrinivas Kandagatla 118869aba794SSrinivas Kandagatla static int __nvmem_cell_read(struct nvmem_device *nvmem, 118969aba794SSrinivas Kandagatla struct nvmem_cell *cell, 119069aba794SSrinivas Kandagatla void *buf, size_t *len) 119169aba794SSrinivas Kandagatla { 119269aba794SSrinivas Kandagatla int rc; 119369aba794SSrinivas Kandagatla 1194795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, cell->offset, buf, cell->bytes); 119569aba794SSrinivas Kandagatla 1196287980e4SArnd Bergmann if (rc) 119769aba794SSrinivas Kandagatla return rc; 119869aba794SSrinivas Kandagatla 119969aba794SSrinivas Kandagatla /* shift bits in-place */ 1200cbf854abSAxel Lin if (cell->bit_offset || cell->nbits) 120169aba794SSrinivas Kandagatla nvmem_shift_read_buffer_in_place(cell, buf); 120269aba794SSrinivas Kandagatla 12033b4a6877SVivek Gautam if (len) 120469aba794SSrinivas Kandagatla *len = cell->bytes; 120569aba794SSrinivas Kandagatla 120669aba794SSrinivas Kandagatla return 0; 120769aba794SSrinivas Kandagatla } 120869aba794SSrinivas Kandagatla 120969aba794SSrinivas Kandagatla /** 121069aba794SSrinivas Kandagatla * nvmem_cell_read() - Read a given nvmem cell 121169aba794SSrinivas Kandagatla * 121269aba794SSrinivas Kandagatla * @cell: nvmem cell to be read. 12133b4a6877SVivek Gautam * @len: pointer to length of cell which will be populated on successful read; 12143b4a6877SVivek Gautam * can be NULL. 121569aba794SSrinivas Kandagatla * 1216b577fafcSBrian Norris * Return: ERR_PTR() on error or a valid pointer to a buffer on success. The 1217b577fafcSBrian Norris * buffer should be freed by the consumer with a kfree(). 121869aba794SSrinivas Kandagatla */ 121969aba794SSrinivas Kandagatla void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len) 122069aba794SSrinivas Kandagatla { 122169aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 122269aba794SSrinivas Kandagatla u8 *buf; 122369aba794SSrinivas Kandagatla int rc; 122469aba794SSrinivas Kandagatla 1225795ddd18SSrinivas Kandagatla if (!nvmem) 122669aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 122769aba794SSrinivas Kandagatla 122869aba794SSrinivas Kandagatla buf = kzalloc(cell->bytes, GFP_KERNEL); 122969aba794SSrinivas Kandagatla if (!buf) 123069aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 123169aba794SSrinivas Kandagatla 123269aba794SSrinivas Kandagatla rc = __nvmem_cell_read(nvmem, cell, buf, len); 1233287980e4SArnd Bergmann if (rc) { 123469aba794SSrinivas Kandagatla kfree(buf); 123569aba794SSrinivas Kandagatla return ERR_PTR(rc); 123669aba794SSrinivas Kandagatla } 123769aba794SSrinivas Kandagatla 123869aba794SSrinivas Kandagatla return buf; 123969aba794SSrinivas Kandagatla } 124069aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_read); 124169aba794SSrinivas Kandagatla 1242f7c04f16SMasahiro Yamada static void *nvmem_cell_prepare_write_buffer(struct nvmem_cell *cell, 124369aba794SSrinivas Kandagatla u8 *_buf, int len) 124469aba794SSrinivas Kandagatla { 124569aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 124669aba794SSrinivas Kandagatla int i, rc, nbits, bit_offset = cell->bit_offset; 124769aba794SSrinivas Kandagatla u8 v, *p, *buf, *b, pbyte, pbits; 124869aba794SSrinivas Kandagatla 124969aba794SSrinivas Kandagatla nbits = cell->nbits; 125069aba794SSrinivas Kandagatla buf = kzalloc(cell->bytes, GFP_KERNEL); 125169aba794SSrinivas Kandagatla if (!buf) 125269aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 125369aba794SSrinivas Kandagatla 125469aba794SSrinivas Kandagatla memcpy(buf, _buf, len); 125569aba794SSrinivas Kandagatla p = b = buf; 125669aba794SSrinivas Kandagatla 125769aba794SSrinivas Kandagatla if (bit_offset) { 125869aba794SSrinivas Kandagatla pbyte = *b; 125969aba794SSrinivas Kandagatla *b <<= bit_offset; 126069aba794SSrinivas Kandagatla 126169aba794SSrinivas Kandagatla /* setup the first byte with lsb bits from nvmem */ 1262795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, cell->offset, &v, 1); 126350808bfcSMathieu Malaterre if (rc) 126450808bfcSMathieu Malaterre goto err; 126569aba794SSrinivas Kandagatla *b++ |= GENMASK(bit_offset - 1, 0) & v; 126669aba794SSrinivas Kandagatla 126769aba794SSrinivas Kandagatla /* setup rest of the byte if any */ 126869aba794SSrinivas Kandagatla for (i = 1; i < cell->bytes; i++) { 126969aba794SSrinivas Kandagatla /* Get last byte bits and shift them towards lsb */ 127069aba794SSrinivas Kandagatla pbits = pbyte >> (BITS_PER_BYTE - 1 - bit_offset); 127169aba794SSrinivas Kandagatla pbyte = *b; 127269aba794SSrinivas Kandagatla p = b; 127369aba794SSrinivas Kandagatla *b <<= bit_offset; 127469aba794SSrinivas Kandagatla *b++ |= pbits; 127569aba794SSrinivas Kandagatla } 127669aba794SSrinivas Kandagatla } 127769aba794SSrinivas Kandagatla 127869aba794SSrinivas Kandagatla /* if it's not end on byte boundary */ 127969aba794SSrinivas Kandagatla if ((nbits + bit_offset) % BITS_PER_BYTE) { 128069aba794SSrinivas Kandagatla /* setup the last byte with msb bits from nvmem */ 1281795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, 128269aba794SSrinivas Kandagatla cell->offset + cell->bytes - 1, &v, 1); 128350808bfcSMathieu Malaterre if (rc) 128450808bfcSMathieu Malaterre goto err; 128569aba794SSrinivas Kandagatla *p |= GENMASK(7, (nbits + bit_offset) % BITS_PER_BYTE) & v; 128669aba794SSrinivas Kandagatla 128769aba794SSrinivas Kandagatla } 128869aba794SSrinivas Kandagatla 128969aba794SSrinivas Kandagatla return buf; 129050808bfcSMathieu Malaterre err: 129150808bfcSMathieu Malaterre kfree(buf); 129250808bfcSMathieu Malaterre return ERR_PTR(rc); 129369aba794SSrinivas Kandagatla } 129469aba794SSrinivas Kandagatla 129569aba794SSrinivas Kandagatla /** 129669aba794SSrinivas Kandagatla * nvmem_cell_write() - Write to a given nvmem cell 129769aba794SSrinivas Kandagatla * 129869aba794SSrinivas Kandagatla * @cell: nvmem cell to be written. 129969aba794SSrinivas Kandagatla * @buf: Buffer to be written. 130069aba794SSrinivas Kandagatla * @len: length of buffer to be written to nvmem cell. 130169aba794SSrinivas Kandagatla * 130269aba794SSrinivas Kandagatla * Return: length of bytes written or negative on failure. 130369aba794SSrinivas Kandagatla */ 130469aba794SSrinivas Kandagatla int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len) 130569aba794SSrinivas Kandagatla { 130669aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 130769aba794SSrinivas Kandagatla int rc; 130869aba794SSrinivas Kandagatla 1309795ddd18SSrinivas Kandagatla if (!nvmem || nvmem->read_only || 131069aba794SSrinivas Kandagatla (cell->bit_offset == 0 && len != cell->bytes)) 131169aba794SSrinivas Kandagatla return -EINVAL; 131269aba794SSrinivas Kandagatla 131369aba794SSrinivas Kandagatla if (cell->bit_offset || cell->nbits) { 131469aba794SSrinivas Kandagatla buf = nvmem_cell_prepare_write_buffer(cell, buf, len); 131569aba794SSrinivas Kandagatla if (IS_ERR(buf)) 131669aba794SSrinivas Kandagatla return PTR_ERR(buf); 131769aba794SSrinivas Kandagatla } 131869aba794SSrinivas Kandagatla 1319795ddd18SSrinivas Kandagatla rc = nvmem_reg_write(nvmem, cell->offset, buf, cell->bytes); 132069aba794SSrinivas Kandagatla 132169aba794SSrinivas Kandagatla /* free the tmp buffer */ 1322ace22170SAxel Lin if (cell->bit_offset || cell->nbits) 132369aba794SSrinivas Kandagatla kfree(buf); 132469aba794SSrinivas Kandagatla 1325287980e4SArnd Bergmann if (rc) 132669aba794SSrinivas Kandagatla return rc; 132769aba794SSrinivas Kandagatla 132869aba794SSrinivas Kandagatla return len; 132969aba794SSrinivas Kandagatla } 133069aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_write); 133169aba794SSrinivas Kandagatla 1332e2a5402eSSrinivas Kandagatla /** 1333d026d70aSLeonard Crestez * nvmem_cell_read_u32() - Read a cell value as an u32 1334d026d70aSLeonard Crestez * 1335d026d70aSLeonard Crestez * @dev: Device that requests the nvmem cell. 1336d026d70aSLeonard Crestez * @cell_id: Name of nvmem cell to read. 1337d026d70aSLeonard Crestez * @val: pointer to output value. 1338d026d70aSLeonard Crestez * 1339d026d70aSLeonard Crestez * Return: 0 on success or negative errno. 1340d026d70aSLeonard Crestez */ 1341d026d70aSLeonard Crestez int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val) 1342d026d70aSLeonard Crestez { 1343d026d70aSLeonard Crestez struct nvmem_cell *cell; 1344d026d70aSLeonard Crestez void *buf; 1345d026d70aSLeonard Crestez size_t len; 1346d026d70aSLeonard Crestez 1347d026d70aSLeonard Crestez cell = nvmem_cell_get(dev, cell_id); 1348d026d70aSLeonard Crestez if (IS_ERR(cell)) 1349d026d70aSLeonard Crestez return PTR_ERR(cell); 1350d026d70aSLeonard Crestez 1351d026d70aSLeonard Crestez buf = nvmem_cell_read(cell, &len); 1352d026d70aSLeonard Crestez if (IS_ERR(buf)) { 1353d026d70aSLeonard Crestez nvmem_cell_put(cell); 1354d026d70aSLeonard Crestez return PTR_ERR(buf); 1355d026d70aSLeonard Crestez } 1356d026d70aSLeonard Crestez if (len != sizeof(*val)) { 1357d026d70aSLeonard Crestez kfree(buf); 1358d026d70aSLeonard Crestez nvmem_cell_put(cell); 1359d026d70aSLeonard Crestez return -EINVAL; 1360d026d70aSLeonard Crestez } 1361d026d70aSLeonard Crestez memcpy(val, buf, sizeof(*val)); 1362d026d70aSLeonard Crestez 1363d026d70aSLeonard Crestez kfree(buf); 1364d026d70aSLeonard Crestez nvmem_cell_put(cell); 1365d026d70aSLeonard Crestez return 0; 1366d026d70aSLeonard Crestez } 1367d026d70aSLeonard Crestez EXPORT_SYMBOL_GPL(nvmem_cell_read_u32); 1368d026d70aSLeonard Crestez 1369d026d70aSLeonard Crestez /** 1370e2a5402eSSrinivas Kandagatla * nvmem_device_cell_read() - Read a given nvmem device and cell 1371e2a5402eSSrinivas Kandagatla * 1372e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to read from. 1373e2a5402eSSrinivas Kandagatla * @info: nvmem cell info to be read. 1374e2a5402eSSrinivas Kandagatla * @buf: buffer pointer which will be populated on successful read. 1375e2a5402eSSrinivas Kandagatla * 1376e2a5402eSSrinivas Kandagatla * Return: length of successful bytes read on success and negative 1377e2a5402eSSrinivas Kandagatla * error code on error. 1378e2a5402eSSrinivas Kandagatla */ 1379e2a5402eSSrinivas Kandagatla ssize_t nvmem_device_cell_read(struct nvmem_device *nvmem, 1380e2a5402eSSrinivas Kandagatla struct nvmem_cell_info *info, void *buf) 1381e2a5402eSSrinivas Kandagatla { 1382e2a5402eSSrinivas Kandagatla struct nvmem_cell cell; 1383e2a5402eSSrinivas Kandagatla int rc; 1384e2a5402eSSrinivas Kandagatla ssize_t len; 1385e2a5402eSSrinivas Kandagatla 1386795ddd18SSrinivas Kandagatla if (!nvmem) 1387e2a5402eSSrinivas Kandagatla return -EINVAL; 1388e2a5402eSSrinivas Kandagatla 1389e2a5402eSSrinivas Kandagatla rc = nvmem_cell_info_to_nvmem_cell(nvmem, info, &cell); 1390287980e4SArnd Bergmann if (rc) 1391e2a5402eSSrinivas Kandagatla return rc; 1392e2a5402eSSrinivas Kandagatla 1393e2a5402eSSrinivas Kandagatla rc = __nvmem_cell_read(nvmem, &cell, buf, &len); 1394287980e4SArnd Bergmann if (rc) 1395e2a5402eSSrinivas Kandagatla return rc; 1396e2a5402eSSrinivas Kandagatla 1397e2a5402eSSrinivas Kandagatla return len; 1398e2a5402eSSrinivas Kandagatla } 1399e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_cell_read); 1400e2a5402eSSrinivas Kandagatla 1401e2a5402eSSrinivas Kandagatla /** 1402e2a5402eSSrinivas Kandagatla * nvmem_device_cell_write() - Write cell to a given nvmem device 1403e2a5402eSSrinivas Kandagatla * 1404e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to be written to. 140529143268SVivek Gautam * @info: nvmem cell info to be written. 1406e2a5402eSSrinivas Kandagatla * @buf: buffer to be written to cell. 1407e2a5402eSSrinivas Kandagatla * 1408e2a5402eSSrinivas Kandagatla * Return: length of bytes written or negative error code on failure. 140948f63a2cSBartosz Golaszewski */ 1410e2a5402eSSrinivas Kandagatla int nvmem_device_cell_write(struct nvmem_device *nvmem, 1411e2a5402eSSrinivas Kandagatla struct nvmem_cell_info *info, void *buf) 1412e2a5402eSSrinivas Kandagatla { 1413e2a5402eSSrinivas Kandagatla struct nvmem_cell cell; 1414e2a5402eSSrinivas Kandagatla int rc; 1415e2a5402eSSrinivas Kandagatla 1416795ddd18SSrinivas Kandagatla if (!nvmem) 1417e2a5402eSSrinivas Kandagatla return -EINVAL; 1418e2a5402eSSrinivas Kandagatla 1419e2a5402eSSrinivas Kandagatla rc = nvmem_cell_info_to_nvmem_cell(nvmem, info, &cell); 1420287980e4SArnd Bergmann if (rc) 1421e2a5402eSSrinivas Kandagatla return rc; 1422e2a5402eSSrinivas Kandagatla 1423e2a5402eSSrinivas Kandagatla return nvmem_cell_write(&cell, buf, cell.bytes); 1424e2a5402eSSrinivas Kandagatla } 1425e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_cell_write); 1426e2a5402eSSrinivas Kandagatla 1427e2a5402eSSrinivas Kandagatla /** 1428e2a5402eSSrinivas Kandagatla * nvmem_device_read() - Read from a given nvmem device 1429e2a5402eSSrinivas Kandagatla * 1430e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to read from. 1431e2a5402eSSrinivas Kandagatla * @offset: offset in nvmem device. 1432e2a5402eSSrinivas Kandagatla * @bytes: number of bytes to read. 1433e2a5402eSSrinivas Kandagatla * @buf: buffer pointer which will be populated on successful read. 1434e2a5402eSSrinivas Kandagatla * 1435e2a5402eSSrinivas Kandagatla * Return: length of successful bytes read on success and negative 1436e2a5402eSSrinivas Kandagatla * error code on error. 1437e2a5402eSSrinivas Kandagatla */ 1438e2a5402eSSrinivas Kandagatla int nvmem_device_read(struct nvmem_device *nvmem, 1439e2a5402eSSrinivas Kandagatla unsigned int offset, 1440e2a5402eSSrinivas Kandagatla size_t bytes, void *buf) 1441e2a5402eSSrinivas Kandagatla { 1442e2a5402eSSrinivas Kandagatla int rc; 1443e2a5402eSSrinivas Kandagatla 1444795ddd18SSrinivas Kandagatla if (!nvmem) 1445e2a5402eSSrinivas Kandagatla return -EINVAL; 1446e2a5402eSSrinivas Kandagatla 1447795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, offset, buf, bytes); 1448e2a5402eSSrinivas Kandagatla 1449287980e4SArnd Bergmann if (rc) 1450e2a5402eSSrinivas Kandagatla return rc; 1451e2a5402eSSrinivas Kandagatla 1452e2a5402eSSrinivas Kandagatla return bytes; 1453e2a5402eSSrinivas Kandagatla } 1454e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_read); 1455e2a5402eSSrinivas Kandagatla 1456e2a5402eSSrinivas Kandagatla /** 1457e2a5402eSSrinivas Kandagatla * nvmem_device_write() - Write cell to a given nvmem device 1458e2a5402eSSrinivas Kandagatla * 1459e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to be written to. 1460e2a5402eSSrinivas Kandagatla * @offset: offset in nvmem device. 1461e2a5402eSSrinivas Kandagatla * @bytes: number of bytes to write. 1462e2a5402eSSrinivas Kandagatla * @buf: buffer to be written. 1463e2a5402eSSrinivas Kandagatla * 1464e2a5402eSSrinivas Kandagatla * Return: length of bytes written or negative error code on failure. 146548f63a2cSBartosz Golaszewski */ 1466e2a5402eSSrinivas Kandagatla int nvmem_device_write(struct nvmem_device *nvmem, 1467e2a5402eSSrinivas Kandagatla unsigned int offset, 1468e2a5402eSSrinivas Kandagatla size_t bytes, void *buf) 1469e2a5402eSSrinivas Kandagatla { 1470e2a5402eSSrinivas Kandagatla int rc; 1471e2a5402eSSrinivas Kandagatla 1472795ddd18SSrinivas Kandagatla if (!nvmem) 1473e2a5402eSSrinivas Kandagatla return -EINVAL; 1474e2a5402eSSrinivas Kandagatla 1475795ddd18SSrinivas Kandagatla rc = nvmem_reg_write(nvmem, offset, buf, bytes); 1476e2a5402eSSrinivas Kandagatla 1477287980e4SArnd Bergmann if (rc) 1478e2a5402eSSrinivas Kandagatla return rc; 1479e2a5402eSSrinivas Kandagatla 1480e2a5402eSSrinivas Kandagatla 1481e2a5402eSSrinivas Kandagatla return bytes; 1482e2a5402eSSrinivas Kandagatla } 1483e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_write); 1484e2a5402eSSrinivas Kandagatla 1485d7b9fd16SBartosz Golaszewski /** 1486b985f4cbSBartosz Golaszewski * nvmem_add_cell_table() - register a table of cell info entries 1487b985f4cbSBartosz Golaszewski * 1488b985f4cbSBartosz Golaszewski * @table: table of cell info entries 1489b985f4cbSBartosz Golaszewski */ 1490b985f4cbSBartosz Golaszewski void nvmem_add_cell_table(struct nvmem_cell_table *table) 1491b985f4cbSBartosz Golaszewski { 1492b985f4cbSBartosz Golaszewski mutex_lock(&nvmem_cell_mutex); 1493b985f4cbSBartosz Golaszewski list_add_tail(&table->node, &nvmem_cell_tables); 1494b985f4cbSBartosz Golaszewski mutex_unlock(&nvmem_cell_mutex); 1495b985f4cbSBartosz Golaszewski } 1496b985f4cbSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_add_cell_table); 1497b985f4cbSBartosz Golaszewski 1498b985f4cbSBartosz Golaszewski /** 1499b985f4cbSBartosz Golaszewski * nvmem_del_cell_table() - remove a previously registered cell info table 1500b985f4cbSBartosz Golaszewski * 1501b985f4cbSBartosz Golaszewski * @table: table of cell info entries 1502b985f4cbSBartosz Golaszewski */ 1503b985f4cbSBartosz Golaszewski void nvmem_del_cell_table(struct nvmem_cell_table *table) 1504b985f4cbSBartosz Golaszewski { 1505b985f4cbSBartosz Golaszewski mutex_lock(&nvmem_cell_mutex); 1506b985f4cbSBartosz Golaszewski list_del(&table->node); 1507b985f4cbSBartosz Golaszewski mutex_unlock(&nvmem_cell_mutex); 1508b985f4cbSBartosz Golaszewski } 1509b985f4cbSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_del_cell_table); 1510b985f4cbSBartosz Golaszewski 1511b985f4cbSBartosz Golaszewski /** 1512506157beSBartosz Golaszewski * nvmem_add_cell_lookups() - register a list of cell lookup entries 1513506157beSBartosz Golaszewski * 1514506157beSBartosz Golaszewski * @entries: array of cell lookup entries 1515506157beSBartosz Golaszewski * @nentries: number of cell lookup entries in the array 1516506157beSBartosz Golaszewski */ 1517506157beSBartosz Golaszewski void nvmem_add_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries) 1518506157beSBartosz Golaszewski { 1519506157beSBartosz Golaszewski int i; 1520506157beSBartosz Golaszewski 1521506157beSBartosz Golaszewski mutex_lock(&nvmem_lookup_mutex); 1522506157beSBartosz Golaszewski for (i = 0; i < nentries; i++) 1523506157beSBartosz Golaszewski list_add_tail(&entries[i].node, &nvmem_lookup_list); 1524506157beSBartosz Golaszewski mutex_unlock(&nvmem_lookup_mutex); 1525506157beSBartosz Golaszewski } 1526506157beSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_add_cell_lookups); 1527506157beSBartosz Golaszewski 1528506157beSBartosz Golaszewski /** 1529506157beSBartosz Golaszewski * nvmem_del_cell_lookups() - remove a list of previously added cell lookup 1530506157beSBartosz Golaszewski * entries 1531506157beSBartosz Golaszewski * 1532506157beSBartosz Golaszewski * @entries: array of cell lookup entries 1533506157beSBartosz Golaszewski * @nentries: number of cell lookup entries in the array 1534506157beSBartosz Golaszewski */ 1535506157beSBartosz Golaszewski void nvmem_del_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries) 1536506157beSBartosz Golaszewski { 1537506157beSBartosz Golaszewski int i; 1538506157beSBartosz Golaszewski 1539506157beSBartosz Golaszewski mutex_lock(&nvmem_lookup_mutex); 1540506157beSBartosz Golaszewski for (i = 0; i < nentries; i++) 1541506157beSBartosz Golaszewski list_del(&entries[i].node); 1542506157beSBartosz Golaszewski mutex_unlock(&nvmem_lookup_mutex); 1543506157beSBartosz Golaszewski } 1544506157beSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_del_cell_lookups); 1545506157beSBartosz Golaszewski 1546506157beSBartosz Golaszewski /** 1547d7b9fd16SBartosz Golaszewski * nvmem_dev_name() - Get the name of a given nvmem device. 1548d7b9fd16SBartosz Golaszewski * 1549d7b9fd16SBartosz Golaszewski * @nvmem: nvmem device. 1550d7b9fd16SBartosz Golaszewski * 1551d7b9fd16SBartosz Golaszewski * Return: name of the nvmem device. 1552d7b9fd16SBartosz Golaszewski */ 1553d7b9fd16SBartosz Golaszewski const char *nvmem_dev_name(struct nvmem_device *nvmem) 1554d7b9fd16SBartosz Golaszewski { 1555d7b9fd16SBartosz Golaszewski return dev_name(&nvmem->dev); 1556d7b9fd16SBartosz Golaszewski } 1557d7b9fd16SBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_dev_name); 1558d7b9fd16SBartosz Golaszewski 1559eace75cfSSrinivas Kandagatla static int __init nvmem_init(void) 1560eace75cfSSrinivas Kandagatla { 1561eace75cfSSrinivas Kandagatla return bus_register(&nvmem_bus_type); 1562eace75cfSSrinivas Kandagatla } 1563eace75cfSSrinivas Kandagatla 1564eace75cfSSrinivas Kandagatla static void __exit nvmem_exit(void) 1565eace75cfSSrinivas Kandagatla { 1566eace75cfSSrinivas Kandagatla bus_unregister(&nvmem_bus_type); 1567eace75cfSSrinivas Kandagatla } 1568eace75cfSSrinivas Kandagatla 1569eace75cfSSrinivas Kandagatla subsys_initcall(nvmem_init); 1570eace75cfSSrinivas Kandagatla module_exit(nvmem_exit); 1571eace75cfSSrinivas Kandagatla 1572eace75cfSSrinivas Kandagatla MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org"); 1573eace75cfSSrinivas Kandagatla MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com"); 1574eace75cfSSrinivas Kandagatla MODULE_DESCRIPTION("nvmem Driver Core"); 1575eace75cfSSrinivas Kandagatla MODULE_LICENSE("GPL v2"); 1576