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> 21ae0c2d72SSrinivas Kandagatla #include "nvmem.h" 22b6c217abSAndrew Lunn 23eace75cfSSrinivas Kandagatla struct nvmem_cell { 24eace75cfSSrinivas Kandagatla const char *name; 25eace75cfSSrinivas Kandagatla int offset; 26eace75cfSSrinivas Kandagatla int bytes; 27eace75cfSSrinivas Kandagatla int bit_offset; 28eace75cfSSrinivas Kandagatla int nbits; 290749aa25SSrinivas Kandagatla struct device_node *np; 30eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem; 31eace75cfSSrinivas Kandagatla struct list_head node; 32eace75cfSSrinivas Kandagatla }; 33eace75cfSSrinivas Kandagatla 34eace75cfSSrinivas Kandagatla static DEFINE_MUTEX(nvmem_mutex); 35eace75cfSSrinivas Kandagatla static DEFINE_IDA(nvmem_ida); 36eace75cfSSrinivas Kandagatla 37b985f4cbSBartosz Golaszewski static DEFINE_MUTEX(nvmem_cell_mutex); 38b985f4cbSBartosz Golaszewski static LIST_HEAD(nvmem_cell_tables); 39b985f4cbSBartosz Golaszewski 40506157beSBartosz Golaszewski static DEFINE_MUTEX(nvmem_lookup_mutex); 41506157beSBartosz Golaszewski static LIST_HEAD(nvmem_lookup_list); 42506157beSBartosz Golaszewski 43bee1138bSBartosz Golaszewski static BLOCKING_NOTIFIER_HEAD(nvmem_notifier); 44bee1138bSBartosz Golaszewski 45a8b44d5dSAndy Shevchenko 46795ddd18SSrinivas Kandagatla static int nvmem_reg_read(struct nvmem_device *nvmem, unsigned int offset, 47795ddd18SSrinivas Kandagatla void *val, size_t bytes) 48795ddd18SSrinivas Kandagatla { 49795ddd18SSrinivas Kandagatla if (nvmem->reg_read) 50795ddd18SSrinivas Kandagatla return nvmem->reg_read(nvmem->priv, offset, val, bytes); 51795ddd18SSrinivas Kandagatla 52795ddd18SSrinivas Kandagatla return -EINVAL; 53795ddd18SSrinivas Kandagatla } 54795ddd18SSrinivas Kandagatla 55795ddd18SSrinivas Kandagatla static int nvmem_reg_write(struct nvmem_device *nvmem, unsigned int offset, 56795ddd18SSrinivas Kandagatla void *val, size_t bytes) 57795ddd18SSrinivas Kandagatla { 582a127da4SKhouloud Touil int ret; 592a127da4SKhouloud Touil 602a127da4SKhouloud Touil if (nvmem->reg_write) { 612a127da4SKhouloud Touil gpiod_set_value_cansleep(nvmem->wp_gpio, 0); 622a127da4SKhouloud Touil ret = nvmem->reg_write(nvmem->priv, offset, val, bytes); 632a127da4SKhouloud Touil gpiod_set_value_cansleep(nvmem->wp_gpio, 1); 642a127da4SKhouloud Touil return ret; 652a127da4SKhouloud Touil } 66795ddd18SSrinivas Kandagatla 67795ddd18SSrinivas Kandagatla return -EINVAL; 68795ddd18SSrinivas Kandagatla } 69eace75cfSSrinivas Kandagatla 70eace75cfSSrinivas Kandagatla static void nvmem_release(struct device *dev) 71eace75cfSSrinivas Kandagatla { 72eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem = to_nvmem_device(dev); 73eace75cfSSrinivas Kandagatla 74eace75cfSSrinivas Kandagatla ida_simple_remove(&nvmem_ida, nvmem->id); 75eace75cfSSrinivas Kandagatla kfree(nvmem); 76eace75cfSSrinivas Kandagatla } 77eace75cfSSrinivas Kandagatla 78eace75cfSSrinivas Kandagatla static const struct device_type nvmem_provider_type = { 79eace75cfSSrinivas Kandagatla .release = nvmem_release, 80eace75cfSSrinivas Kandagatla }; 81eace75cfSSrinivas Kandagatla 82eace75cfSSrinivas Kandagatla static struct bus_type nvmem_bus_type = { 83eace75cfSSrinivas Kandagatla .name = "nvmem", 84eace75cfSSrinivas Kandagatla }; 85eace75cfSSrinivas Kandagatla 86eace75cfSSrinivas Kandagatla static void nvmem_cell_drop(struct nvmem_cell *cell) 87eace75cfSSrinivas Kandagatla { 88bee1138bSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_REMOVE, cell); 89c7235ee3SBartosz Golaszewski mutex_lock(&nvmem_mutex); 90eace75cfSSrinivas Kandagatla list_del(&cell->node); 91c7235ee3SBartosz Golaszewski mutex_unlock(&nvmem_mutex); 920749aa25SSrinivas Kandagatla of_node_put(cell->np); 9316bb7abcSBitan Biswas kfree_const(cell->name); 94eace75cfSSrinivas Kandagatla kfree(cell); 95eace75cfSSrinivas Kandagatla } 96eace75cfSSrinivas Kandagatla 97eace75cfSSrinivas Kandagatla static void nvmem_device_remove_all_cells(const struct nvmem_device *nvmem) 98eace75cfSSrinivas Kandagatla { 991852183eSBartosz Golaszewski struct nvmem_cell *cell, *p; 100eace75cfSSrinivas Kandagatla 101c7235ee3SBartosz Golaszewski list_for_each_entry_safe(cell, p, &nvmem->cells, node) 102eace75cfSSrinivas Kandagatla nvmem_cell_drop(cell); 103eace75cfSSrinivas Kandagatla } 104eace75cfSSrinivas Kandagatla 105eace75cfSSrinivas Kandagatla static void nvmem_cell_add(struct nvmem_cell *cell) 106eace75cfSSrinivas Kandagatla { 107c7235ee3SBartosz Golaszewski mutex_lock(&nvmem_mutex); 108c7235ee3SBartosz Golaszewski list_add_tail(&cell->node, &cell->nvmem->cells); 109c7235ee3SBartosz Golaszewski mutex_unlock(&nvmem_mutex); 110bee1138bSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_ADD, cell); 111eace75cfSSrinivas Kandagatla } 112eace75cfSSrinivas Kandagatla 113eace75cfSSrinivas Kandagatla static int nvmem_cell_info_to_nvmem_cell(struct nvmem_device *nvmem, 114eace75cfSSrinivas Kandagatla const struct nvmem_cell_info *info, 115eace75cfSSrinivas Kandagatla struct nvmem_cell *cell) 116eace75cfSSrinivas Kandagatla { 117eace75cfSSrinivas Kandagatla cell->nvmem = nvmem; 118eace75cfSSrinivas Kandagatla cell->offset = info->offset; 119eace75cfSSrinivas Kandagatla cell->bytes = info->bytes; 12016bb7abcSBitan Biswas cell->name = kstrdup_const(info->name, GFP_KERNEL); 12116bb7abcSBitan Biswas if (!cell->name) 12216bb7abcSBitan Biswas return -ENOMEM; 123eace75cfSSrinivas Kandagatla 124eace75cfSSrinivas Kandagatla cell->bit_offset = info->bit_offset; 125eace75cfSSrinivas Kandagatla cell->nbits = info->nbits; 126eace75cfSSrinivas Kandagatla 127eace75cfSSrinivas Kandagatla if (cell->nbits) 128eace75cfSSrinivas Kandagatla cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset, 129eace75cfSSrinivas Kandagatla BITS_PER_BYTE); 130eace75cfSSrinivas Kandagatla 131eace75cfSSrinivas Kandagatla if (!IS_ALIGNED(cell->offset, nvmem->stride)) { 132eace75cfSSrinivas Kandagatla dev_err(&nvmem->dev, 133eace75cfSSrinivas Kandagatla "cell %s unaligned to nvmem stride %d\n", 134eace75cfSSrinivas Kandagatla cell->name, nvmem->stride); 135eace75cfSSrinivas Kandagatla return -EINVAL; 136eace75cfSSrinivas Kandagatla } 137eace75cfSSrinivas Kandagatla 138eace75cfSSrinivas Kandagatla return 0; 139eace75cfSSrinivas Kandagatla } 140eace75cfSSrinivas Kandagatla 141b3db17e4SAndrew Lunn /** 142b3db17e4SAndrew Lunn * nvmem_add_cells() - Add cell information to an nvmem device 143b3db17e4SAndrew Lunn * 144b3db17e4SAndrew Lunn * @nvmem: nvmem device to add cells to. 145b3db17e4SAndrew Lunn * @info: nvmem cell info to add to the device 146b3db17e4SAndrew Lunn * @ncells: number of cells in info 147b3db17e4SAndrew Lunn * 148b3db17e4SAndrew Lunn * Return: 0 or negative error code on failure. 149b3db17e4SAndrew Lunn */ 150ef92ab30SSrinivas Kandagatla static int nvmem_add_cells(struct nvmem_device *nvmem, 151b3db17e4SAndrew Lunn const struct nvmem_cell_info *info, 152b3db17e4SAndrew Lunn int ncells) 153eace75cfSSrinivas Kandagatla { 154eace75cfSSrinivas Kandagatla struct nvmem_cell **cells; 155eace75cfSSrinivas Kandagatla int i, rval; 156eace75cfSSrinivas Kandagatla 157b3db17e4SAndrew Lunn cells = kcalloc(ncells, sizeof(*cells), GFP_KERNEL); 158eace75cfSSrinivas Kandagatla if (!cells) 159eace75cfSSrinivas Kandagatla return -ENOMEM; 160eace75cfSSrinivas Kandagatla 161b3db17e4SAndrew Lunn for (i = 0; i < ncells; i++) { 162eace75cfSSrinivas Kandagatla cells[i] = kzalloc(sizeof(**cells), GFP_KERNEL); 163eace75cfSSrinivas Kandagatla if (!cells[i]) { 164eace75cfSSrinivas Kandagatla rval = -ENOMEM; 165eace75cfSSrinivas Kandagatla goto err; 166eace75cfSSrinivas Kandagatla } 167eace75cfSSrinivas Kandagatla 168eace75cfSSrinivas Kandagatla rval = nvmem_cell_info_to_nvmem_cell(nvmem, &info[i], cells[i]); 169287980e4SArnd Bergmann if (rval) { 170eace75cfSSrinivas Kandagatla kfree(cells[i]); 171eace75cfSSrinivas Kandagatla goto err; 172eace75cfSSrinivas Kandagatla } 173eace75cfSSrinivas Kandagatla 174eace75cfSSrinivas Kandagatla nvmem_cell_add(cells[i]); 175eace75cfSSrinivas Kandagatla } 176eace75cfSSrinivas Kandagatla 177eace75cfSSrinivas Kandagatla /* remove tmp array */ 178eace75cfSSrinivas Kandagatla kfree(cells); 179eace75cfSSrinivas Kandagatla 180eace75cfSSrinivas Kandagatla return 0; 181eace75cfSSrinivas Kandagatla err: 182dfdf1414SRasmus Villemoes while (i--) 183eace75cfSSrinivas Kandagatla nvmem_cell_drop(cells[i]); 184eace75cfSSrinivas Kandagatla 185dfdf1414SRasmus Villemoes kfree(cells); 186dfdf1414SRasmus Villemoes 187eace75cfSSrinivas Kandagatla return rval; 188eace75cfSSrinivas Kandagatla } 189eace75cfSSrinivas Kandagatla 190bee1138bSBartosz Golaszewski /** 191bee1138bSBartosz Golaszewski * nvmem_register_notifier() - Register a notifier block for nvmem events. 192bee1138bSBartosz Golaszewski * 193bee1138bSBartosz Golaszewski * @nb: notifier block to be called on nvmem events. 194bee1138bSBartosz Golaszewski * 195bee1138bSBartosz Golaszewski * Return: 0 on success, negative error number on failure. 196bee1138bSBartosz Golaszewski */ 197bee1138bSBartosz Golaszewski int nvmem_register_notifier(struct notifier_block *nb) 198bee1138bSBartosz Golaszewski { 199bee1138bSBartosz Golaszewski return blocking_notifier_chain_register(&nvmem_notifier, nb); 200bee1138bSBartosz Golaszewski } 201bee1138bSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_register_notifier); 202bee1138bSBartosz Golaszewski 203bee1138bSBartosz Golaszewski /** 204bee1138bSBartosz Golaszewski * nvmem_unregister_notifier() - Unregister a notifier block for nvmem events. 205bee1138bSBartosz Golaszewski * 206bee1138bSBartosz Golaszewski * @nb: notifier block to be unregistered. 207bee1138bSBartosz Golaszewski * 208bee1138bSBartosz Golaszewski * Return: 0 on success, negative error number on failure. 209bee1138bSBartosz Golaszewski */ 210bee1138bSBartosz Golaszewski int nvmem_unregister_notifier(struct notifier_block *nb) 211bee1138bSBartosz Golaszewski { 212bee1138bSBartosz Golaszewski return blocking_notifier_chain_unregister(&nvmem_notifier, nb); 213bee1138bSBartosz Golaszewski } 214bee1138bSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_unregister_notifier); 215bee1138bSBartosz Golaszewski 216b985f4cbSBartosz Golaszewski static int nvmem_add_cells_from_table(struct nvmem_device *nvmem) 217b985f4cbSBartosz Golaszewski { 218b985f4cbSBartosz Golaszewski const struct nvmem_cell_info *info; 219b985f4cbSBartosz Golaszewski struct nvmem_cell_table *table; 220b985f4cbSBartosz Golaszewski struct nvmem_cell *cell; 221b985f4cbSBartosz Golaszewski int rval = 0, i; 222b985f4cbSBartosz Golaszewski 223b985f4cbSBartosz Golaszewski mutex_lock(&nvmem_cell_mutex); 224b985f4cbSBartosz Golaszewski list_for_each_entry(table, &nvmem_cell_tables, node) { 225b985f4cbSBartosz Golaszewski if (strcmp(nvmem_dev_name(nvmem), table->nvmem_name) == 0) { 226b985f4cbSBartosz Golaszewski for (i = 0; i < table->ncells; i++) { 227b985f4cbSBartosz Golaszewski info = &table->cells[i]; 228b985f4cbSBartosz Golaszewski 229b985f4cbSBartosz Golaszewski cell = kzalloc(sizeof(*cell), GFP_KERNEL); 230b985f4cbSBartosz Golaszewski if (!cell) { 231b985f4cbSBartosz Golaszewski rval = -ENOMEM; 232b985f4cbSBartosz Golaszewski goto out; 233b985f4cbSBartosz Golaszewski } 234b985f4cbSBartosz Golaszewski 235b985f4cbSBartosz Golaszewski rval = nvmem_cell_info_to_nvmem_cell(nvmem, 236b985f4cbSBartosz Golaszewski info, 237b985f4cbSBartosz Golaszewski cell); 238b985f4cbSBartosz Golaszewski if (rval) { 239b985f4cbSBartosz Golaszewski kfree(cell); 240b985f4cbSBartosz Golaszewski goto out; 241b985f4cbSBartosz Golaszewski } 242b985f4cbSBartosz Golaszewski 243b985f4cbSBartosz Golaszewski nvmem_cell_add(cell); 244b985f4cbSBartosz Golaszewski } 245b985f4cbSBartosz Golaszewski } 246b985f4cbSBartosz Golaszewski } 247b985f4cbSBartosz Golaszewski 248b985f4cbSBartosz Golaszewski out: 249b985f4cbSBartosz Golaszewski mutex_unlock(&nvmem_cell_mutex); 250b985f4cbSBartosz Golaszewski return rval; 251b985f4cbSBartosz Golaszewski } 252b985f4cbSBartosz Golaszewski 253e888d445SBartosz Golaszewski static struct nvmem_cell * 254506157beSBartosz Golaszewski nvmem_find_cell_by_name(struct nvmem_device *nvmem, const char *cell_id) 255506157beSBartosz Golaszewski { 2561c832674SAlban Bedel struct nvmem_cell *iter, *cell = NULL; 257506157beSBartosz Golaszewski 258506157beSBartosz Golaszewski mutex_lock(&nvmem_mutex); 2591c832674SAlban Bedel list_for_each_entry(iter, &nvmem->cells, node) { 2601c832674SAlban Bedel if (strcmp(cell_id, iter->name) == 0) { 2611c832674SAlban Bedel cell = iter; 262506157beSBartosz Golaszewski break; 263506157beSBartosz Golaszewski } 2641c832674SAlban Bedel } 265506157beSBartosz Golaszewski mutex_unlock(&nvmem_mutex); 266506157beSBartosz Golaszewski 267506157beSBartosz Golaszewski return cell; 268506157beSBartosz Golaszewski } 269506157beSBartosz Golaszewski 270e888d445SBartosz Golaszewski static int nvmem_add_cells_from_of(struct nvmem_device *nvmem) 271e888d445SBartosz Golaszewski { 272e888d445SBartosz Golaszewski struct device_node *parent, *child; 273e888d445SBartosz Golaszewski struct device *dev = &nvmem->dev; 274e888d445SBartosz Golaszewski struct nvmem_cell *cell; 275e888d445SBartosz Golaszewski const __be32 *addr; 276e888d445SBartosz Golaszewski int len; 277e888d445SBartosz Golaszewski 278e888d445SBartosz Golaszewski parent = dev->of_node; 279e888d445SBartosz Golaszewski 280e888d445SBartosz Golaszewski for_each_child_of_node(parent, child) { 281e888d445SBartosz Golaszewski addr = of_get_property(child, "reg", &len); 282e888d445SBartosz Golaszewski if (!addr || (len < 2 * sizeof(u32))) { 283e888d445SBartosz Golaszewski dev_err(dev, "nvmem: invalid reg on %pOF\n", child); 284e888d445SBartosz Golaszewski return -EINVAL; 285e888d445SBartosz Golaszewski } 286e888d445SBartosz Golaszewski 287e888d445SBartosz Golaszewski cell = kzalloc(sizeof(*cell), GFP_KERNEL); 288e888d445SBartosz Golaszewski if (!cell) 289e888d445SBartosz Golaszewski return -ENOMEM; 290e888d445SBartosz Golaszewski 291e888d445SBartosz Golaszewski cell->nvmem = nvmem; 2920749aa25SSrinivas Kandagatla cell->np = of_node_get(child); 293e888d445SBartosz Golaszewski cell->offset = be32_to_cpup(addr++); 294e888d445SBartosz Golaszewski cell->bytes = be32_to_cpup(addr); 295badcdff1SRob Herring cell->name = kasprintf(GFP_KERNEL, "%pOFn", child); 296e888d445SBartosz Golaszewski 297e888d445SBartosz Golaszewski addr = of_get_property(child, "bits", &len); 298e888d445SBartosz Golaszewski if (addr && len == (2 * sizeof(u32))) { 299e888d445SBartosz Golaszewski cell->bit_offset = be32_to_cpup(addr++); 300e888d445SBartosz Golaszewski cell->nbits = be32_to_cpup(addr); 301e888d445SBartosz Golaszewski } 302e888d445SBartosz Golaszewski 303e888d445SBartosz Golaszewski if (cell->nbits) 304e888d445SBartosz Golaszewski cell->bytes = DIV_ROUND_UP( 305e888d445SBartosz Golaszewski cell->nbits + cell->bit_offset, 306e888d445SBartosz Golaszewski BITS_PER_BYTE); 307e888d445SBartosz Golaszewski 308e888d445SBartosz Golaszewski if (!IS_ALIGNED(cell->offset, nvmem->stride)) { 309e888d445SBartosz Golaszewski dev_err(dev, "cell %s unaligned to nvmem stride %d\n", 310e888d445SBartosz Golaszewski cell->name, nvmem->stride); 311e888d445SBartosz Golaszewski /* Cells already added will be freed later. */ 31216bb7abcSBitan Biswas kfree_const(cell->name); 313e888d445SBartosz Golaszewski kfree(cell); 314e888d445SBartosz Golaszewski return -EINVAL; 315e888d445SBartosz Golaszewski } 316e888d445SBartosz Golaszewski 317e888d445SBartosz Golaszewski nvmem_cell_add(cell); 318e888d445SBartosz Golaszewski } 319e888d445SBartosz Golaszewski 320e888d445SBartosz Golaszewski return 0; 321e888d445SBartosz Golaszewski } 322e888d445SBartosz Golaszewski 323eace75cfSSrinivas Kandagatla /** 324eace75cfSSrinivas Kandagatla * nvmem_register() - Register a nvmem device for given nvmem_config. 325eace75cfSSrinivas Kandagatla * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem 326eace75cfSSrinivas Kandagatla * 327eace75cfSSrinivas Kandagatla * @config: nvmem device configuration with which nvmem device is created. 328eace75cfSSrinivas Kandagatla * 329eace75cfSSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device 330eace75cfSSrinivas Kandagatla * on success. 331eace75cfSSrinivas Kandagatla */ 332eace75cfSSrinivas Kandagatla 333eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem_register(const struct nvmem_config *config) 334eace75cfSSrinivas Kandagatla { 335eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem; 336eace75cfSSrinivas Kandagatla int rval; 337eace75cfSSrinivas Kandagatla 338eace75cfSSrinivas Kandagatla if (!config->dev) 339eace75cfSSrinivas Kandagatla return ERR_PTR(-EINVAL); 340eace75cfSSrinivas Kandagatla 341eace75cfSSrinivas Kandagatla nvmem = kzalloc(sizeof(*nvmem), GFP_KERNEL); 342eace75cfSSrinivas Kandagatla if (!nvmem) 343eace75cfSSrinivas Kandagatla return ERR_PTR(-ENOMEM); 344eace75cfSSrinivas Kandagatla 345eace75cfSSrinivas Kandagatla rval = ida_simple_get(&nvmem_ida, 0, 0, GFP_KERNEL); 346eace75cfSSrinivas Kandagatla if (rval < 0) { 347eace75cfSSrinivas Kandagatla kfree(nvmem); 348eace75cfSSrinivas Kandagatla return ERR_PTR(rval); 349eace75cfSSrinivas Kandagatla } 35031c6ff51SBartosz Golaszewski 3512a127da4SKhouloud Touil if (config->wp_gpio) 3522a127da4SKhouloud Touil nvmem->wp_gpio = config->wp_gpio; 3532a127da4SKhouloud Touil else 3542a127da4SKhouloud Touil nvmem->wp_gpio = gpiod_get_optional(config->dev, "wp", 3552a127da4SKhouloud Touil GPIOD_OUT_HIGH); 356*f7d8d7dcSBartosz Golaszewski if (IS_ERR(nvmem->wp_gpio)) { 357*f7d8d7dcSBartosz Golaszewski ida_simple_remove(&nvmem_ida, nvmem->id); 358*f7d8d7dcSBartosz Golaszewski rval = PTR_ERR(nvmem->wp_gpio); 359*f7d8d7dcSBartosz Golaszewski kfree(nvmem); 360*f7d8d7dcSBartosz Golaszewski return ERR_PTR(rval); 361*f7d8d7dcSBartosz Golaszewski } 3622a127da4SKhouloud Touil 363c1de7f43SBartosz Golaszewski kref_init(&nvmem->refcnt); 364c7235ee3SBartosz Golaszewski INIT_LIST_HEAD(&nvmem->cells); 365c1de7f43SBartosz Golaszewski 366eace75cfSSrinivas Kandagatla nvmem->id = rval; 367eace75cfSSrinivas Kandagatla nvmem->owner = config->owner; 36817eb18d6SMasahiro Yamada if (!nvmem->owner && config->dev->driver) 36917eb18d6SMasahiro Yamada nvmem->owner = config->dev->driver->owner; 37099897efdSHeiner Kallweit nvmem->stride = config->stride ?: 1; 37199897efdSHeiner Kallweit nvmem->word_size = config->word_size ?: 1; 372795ddd18SSrinivas Kandagatla nvmem->size = config->size; 373eace75cfSSrinivas Kandagatla nvmem->dev.type = &nvmem_provider_type; 374eace75cfSSrinivas Kandagatla nvmem->dev.bus = &nvmem_bus_type; 375eace75cfSSrinivas Kandagatla nvmem->dev.parent = config->dev; 376795ddd18SSrinivas Kandagatla nvmem->priv = config->priv; 37716688453SAlexandre Belloni nvmem->type = config->type; 378795ddd18SSrinivas Kandagatla nvmem->reg_read = config->reg_read; 379795ddd18SSrinivas Kandagatla nvmem->reg_write = config->reg_write; 380517f14d9SBartosz Golaszewski if (!config->no_of_node) 381fc2f9970SHeiner Kallweit nvmem->dev.of_node = config->dev->of_node; 382fd0f4906SAndrey Smirnov 383fd0f4906SAndrey Smirnov if (config->id == -1 && config->name) { 384fd0f4906SAndrey Smirnov dev_set_name(&nvmem->dev, "%s", config->name); 385fd0f4906SAndrey Smirnov } else { 386eace75cfSSrinivas Kandagatla dev_set_name(&nvmem->dev, "%s%d", 3875253193dSAban Bedel config->name ? : "nvmem", 3885253193dSAban Bedel config->name ? config->id : nvmem->id); 389fd0f4906SAndrey Smirnov } 390eace75cfSSrinivas Kandagatla 3911716cfe8SAlban Bedel nvmem->read_only = device_property_present(config->dev, "read-only") || 3921716cfe8SAlban Bedel config->read_only || !nvmem->reg_write; 393eace75cfSSrinivas Kandagatla 394ae0c2d72SSrinivas Kandagatla nvmem->dev.groups = nvmem_sysfs_get_groups(nvmem, config); 395eace75cfSSrinivas Kandagatla 396eace75cfSSrinivas Kandagatla device_initialize(&nvmem->dev); 397eace75cfSSrinivas Kandagatla 398eace75cfSSrinivas Kandagatla dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name); 399eace75cfSSrinivas Kandagatla 400eace75cfSSrinivas Kandagatla rval = device_add(&nvmem->dev); 401b6c217abSAndrew Lunn if (rval) 4023360acdfSJohan Hovold goto err_put_device; 403b6c217abSAndrew Lunn 404b6c217abSAndrew Lunn if (config->compat) { 405ae0c2d72SSrinivas Kandagatla rval = nvmem_sysfs_setup_compat(nvmem, config); 406b6c217abSAndrew Lunn if (rval) 4073360acdfSJohan Hovold goto err_device_del; 408eace75cfSSrinivas Kandagatla } 409eace75cfSSrinivas Kandagatla 410fa72d847SBartosz Golaszewski if (config->cells) { 411fa72d847SBartosz Golaszewski rval = nvmem_add_cells(nvmem, config->cells, config->ncells); 412fa72d847SBartosz Golaszewski if (rval) 413fa72d847SBartosz Golaszewski goto err_teardown_compat; 414fa72d847SBartosz Golaszewski } 415eace75cfSSrinivas Kandagatla 416b985f4cbSBartosz Golaszewski rval = nvmem_add_cells_from_table(nvmem); 417b985f4cbSBartosz Golaszewski if (rval) 418b985f4cbSBartosz Golaszewski goto err_remove_cells; 419b985f4cbSBartosz Golaszewski 420e888d445SBartosz Golaszewski rval = nvmem_add_cells_from_of(nvmem); 421e888d445SBartosz Golaszewski if (rval) 422e888d445SBartosz Golaszewski goto err_remove_cells; 423e888d445SBartosz Golaszewski 424f4853e1cSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_ADD, nvmem); 425bee1138bSBartosz Golaszewski 426eace75cfSSrinivas Kandagatla return nvmem; 4273360acdfSJohan Hovold 428b985f4cbSBartosz Golaszewski err_remove_cells: 429b985f4cbSBartosz Golaszewski nvmem_device_remove_all_cells(nvmem); 430fa72d847SBartosz Golaszewski err_teardown_compat: 431fa72d847SBartosz Golaszewski if (config->compat) 432ae0c2d72SSrinivas Kandagatla nvmem_sysfs_remove_compat(nvmem, config); 4333360acdfSJohan Hovold err_device_del: 4343360acdfSJohan Hovold device_del(&nvmem->dev); 4353360acdfSJohan Hovold err_put_device: 4363360acdfSJohan Hovold put_device(&nvmem->dev); 4373360acdfSJohan Hovold 438b6c217abSAndrew Lunn return ERR_PTR(rval); 439eace75cfSSrinivas Kandagatla } 440eace75cfSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_register); 441eace75cfSSrinivas Kandagatla 442c1de7f43SBartosz Golaszewski static void nvmem_device_release(struct kref *kref) 443c1de7f43SBartosz Golaszewski { 444c1de7f43SBartosz Golaszewski struct nvmem_device *nvmem; 445c1de7f43SBartosz Golaszewski 446c1de7f43SBartosz Golaszewski nvmem = container_of(kref, struct nvmem_device, refcnt); 447c1de7f43SBartosz Golaszewski 448bee1138bSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_REMOVE, nvmem); 449bee1138bSBartosz Golaszewski 450c1de7f43SBartosz Golaszewski if (nvmem->flags & FLAG_COMPAT) 451c1de7f43SBartosz Golaszewski device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); 452c1de7f43SBartosz Golaszewski 453c1de7f43SBartosz Golaszewski nvmem_device_remove_all_cells(nvmem); 454c1de7f43SBartosz Golaszewski device_del(&nvmem->dev); 455c1de7f43SBartosz Golaszewski put_device(&nvmem->dev); 456c1de7f43SBartosz Golaszewski } 457c1de7f43SBartosz Golaszewski 458eace75cfSSrinivas Kandagatla /** 459eace75cfSSrinivas Kandagatla * nvmem_unregister() - Unregister previously registered nvmem device 460eace75cfSSrinivas Kandagatla * 461eace75cfSSrinivas Kandagatla * @nvmem: Pointer to previously registered nvmem device. 462eace75cfSSrinivas Kandagatla */ 463bf58e882SBartosz Golaszewski void nvmem_unregister(struct nvmem_device *nvmem) 464eace75cfSSrinivas Kandagatla { 465c1de7f43SBartosz Golaszewski kref_put(&nvmem->refcnt, nvmem_device_release); 466eace75cfSSrinivas Kandagatla } 467eace75cfSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_unregister); 468eace75cfSSrinivas Kandagatla 469f1f50ecaSAndrey Smirnov static void devm_nvmem_release(struct device *dev, void *res) 470f1f50ecaSAndrey Smirnov { 471bf58e882SBartosz Golaszewski nvmem_unregister(*(struct nvmem_device **)res); 472f1f50ecaSAndrey Smirnov } 473f1f50ecaSAndrey Smirnov 474f1f50ecaSAndrey Smirnov /** 475f1f50ecaSAndrey Smirnov * devm_nvmem_register() - Register a managed nvmem device for given 476f1f50ecaSAndrey Smirnov * nvmem_config. 477f1f50ecaSAndrey Smirnov * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem 478f1f50ecaSAndrey Smirnov * 479b378c779SSrinivas Kandagatla * @dev: Device that uses the nvmem device. 480f1f50ecaSAndrey Smirnov * @config: nvmem device configuration with which nvmem device is created. 481f1f50ecaSAndrey Smirnov * 482f1f50ecaSAndrey Smirnov * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device 483f1f50ecaSAndrey Smirnov * on success. 484f1f50ecaSAndrey Smirnov */ 485f1f50ecaSAndrey Smirnov struct nvmem_device *devm_nvmem_register(struct device *dev, 486f1f50ecaSAndrey Smirnov const struct nvmem_config *config) 487f1f50ecaSAndrey Smirnov { 488f1f50ecaSAndrey Smirnov struct nvmem_device **ptr, *nvmem; 489f1f50ecaSAndrey Smirnov 490f1f50ecaSAndrey Smirnov ptr = devres_alloc(devm_nvmem_release, sizeof(*ptr), GFP_KERNEL); 491f1f50ecaSAndrey Smirnov if (!ptr) 492f1f50ecaSAndrey Smirnov return ERR_PTR(-ENOMEM); 493f1f50ecaSAndrey Smirnov 494f1f50ecaSAndrey Smirnov nvmem = nvmem_register(config); 495f1f50ecaSAndrey Smirnov 496f1f50ecaSAndrey Smirnov if (!IS_ERR(nvmem)) { 497f1f50ecaSAndrey Smirnov *ptr = nvmem; 498f1f50ecaSAndrey Smirnov devres_add(dev, ptr); 499f1f50ecaSAndrey Smirnov } else { 500f1f50ecaSAndrey Smirnov devres_free(ptr); 501f1f50ecaSAndrey Smirnov } 502f1f50ecaSAndrey Smirnov 503f1f50ecaSAndrey Smirnov return nvmem; 504f1f50ecaSAndrey Smirnov } 505f1f50ecaSAndrey Smirnov EXPORT_SYMBOL_GPL(devm_nvmem_register); 506f1f50ecaSAndrey Smirnov 507f1f50ecaSAndrey Smirnov static int devm_nvmem_match(struct device *dev, void *res, void *data) 508f1f50ecaSAndrey Smirnov { 509f1f50ecaSAndrey Smirnov struct nvmem_device **r = res; 510f1f50ecaSAndrey Smirnov 511f1f50ecaSAndrey Smirnov return *r == data; 512f1f50ecaSAndrey Smirnov } 513f1f50ecaSAndrey Smirnov 514f1f50ecaSAndrey Smirnov /** 515f1f50ecaSAndrey Smirnov * devm_nvmem_unregister() - Unregister previously registered managed nvmem 516f1f50ecaSAndrey Smirnov * device. 517f1f50ecaSAndrey Smirnov * 518b378c779SSrinivas Kandagatla * @dev: Device that uses the nvmem device. 519f1f50ecaSAndrey Smirnov * @nvmem: Pointer to previously registered nvmem device. 520f1f50ecaSAndrey Smirnov * 521f1f50ecaSAndrey Smirnov * Return: Will be an negative on error or a zero on success. 522f1f50ecaSAndrey Smirnov */ 523f1f50ecaSAndrey Smirnov int devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem) 524f1f50ecaSAndrey Smirnov { 525f1f50ecaSAndrey Smirnov return devres_release(dev, devm_nvmem_release, devm_nvmem_match, nvmem); 526f1f50ecaSAndrey Smirnov } 527f1f50ecaSAndrey Smirnov EXPORT_SYMBOL(devm_nvmem_unregister); 528f1f50ecaSAndrey Smirnov 5298c2a2b8cSThomas Bogendoerfer static struct nvmem_device *__nvmem_device_get(void *data, 5308c2a2b8cSThomas Bogendoerfer int (*match)(struct device *dev, const void *data)) 53169aba794SSrinivas Kandagatla { 53269aba794SSrinivas Kandagatla struct nvmem_device *nvmem = NULL; 5338c2a2b8cSThomas Bogendoerfer struct device *dev; 53469aba794SSrinivas Kandagatla 535c7235ee3SBartosz Golaszewski mutex_lock(&nvmem_mutex); 5368c2a2b8cSThomas Bogendoerfer dev = bus_find_device(&nvmem_bus_type, NULL, data, match); 5378c2a2b8cSThomas Bogendoerfer if (dev) 5388c2a2b8cSThomas Bogendoerfer nvmem = to_nvmem_device(dev); 53969aba794SSrinivas Kandagatla mutex_unlock(&nvmem_mutex); 540c7235ee3SBartosz Golaszewski if (!nvmem) 541c7235ee3SBartosz Golaszewski return ERR_PTR(-EPROBE_DEFER); 54269aba794SSrinivas Kandagatla 54369aba794SSrinivas Kandagatla if (!try_module_get(nvmem->owner)) { 54469aba794SSrinivas Kandagatla dev_err(&nvmem->dev, 54569aba794SSrinivas Kandagatla "could not increase module refcount for cell %s\n", 5465db652c9SBartosz Golaszewski nvmem_dev_name(nvmem)); 54769aba794SSrinivas Kandagatla 54873e9dc4dSAlban Bedel put_device(&nvmem->dev); 54969aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 55069aba794SSrinivas Kandagatla } 55169aba794SSrinivas Kandagatla 552c1de7f43SBartosz Golaszewski kref_get(&nvmem->refcnt); 553c1de7f43SBartosz Golaszewski 55469aba794SSrinivas Kandagatla return nvmem; 55569aba794SSrinivas Kandagatla } 55669aba794SSrinivas Kandagatla 55769aba794SSrinivas Kandagatla static void __nvmem_device_put(struct nvmem_device *nvmem) 55869aba794SSrinivas Kandagatla { 55973e9dc4dSAlban Bedel put_device(&nvmem->dev); 56069aba794SSrinivas Kandagatla module_put(nvmem->owner); 561c1de7f43SBartosz Golaszewski kref_put(&nvmem->refcnt, nvmem_device_release); 56269aba794SSrinivas Kandagatla } 56369aba794SSrinivas Kandagatla 564e701c67cSMasahiro Yamada #if IS_ENABLED(CONFIG_OF) 565e2a5402eSSrinivas Kandagatla /** 566e2a5402eSSrinivas Kandagatla * of_nvmem_device_get() - Get nvmem device from a given id 567e2a5402eSSrinivas Kandagatla * 56829143268SVivek Gautam * @np: Device tree node that uses the nvmem device. 569e2a5402eSSrinivas Kandagatla * @id: nvmem name from nvmem-names property. 570e2a5402eSSrinivas Kandagatla * 571e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device 572e2a5402eSSrinivas Kandagatla * on success. 573e2a5402eSSrinivas Kandagatla */ 574e2a5402eSSrinivas Kandagatla struct nvmem_device *of_nvmem_device_get(struct device_node *np, const char *id) 575e2a5402eSSrinivas Kandagatla { 576e2a5402eSSrinivas Kandagatla 577e2a5402eSSrinivas Kandagatla struct device_node *nvmem_np; 578d4e7fef1SAlban Bedel int index = 0; 579e2a5402eSSrinivas Kandagatla 580d4e7fef1SAlban Bedel if (id) 581e2a5402eSSrinivas Kandagatla index = of_property_match_string(np, "nvmem-names", id); 582e2a5402eSSrinivas Kandagatla 583e2a5402eSSrinivas Kandagatla nvmem_np = of_parse_phandle(np, "nvmem", index); 584e2a5402eSSrinivas Kandagatla if (!nvmem_np) 585d4e7fef1SAlban Bedel return ERR_PTR(-ENOENT); 586e2a5402eSSrinivas Kandagatla 5878c2a2b8cSThomas Bogendoerfer return __nvmem_device_get(nvmem_np, device_match_of_node); 588e2a5402eSSrinivas Kandagatla } 589e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_nvmem_device_get); 590e2a5402eSSrinivas Kandagatla #endif 591e2a5402eSSrinivas Kandagatla 592e2a5402eSSrinivas Kandagatla /** 593e2a5402eSSrinivas Kandagatla * nvmem_device_get() - Get nvmem device from a given id 594e2a5402eSSrinivas Kandagatla * 59529143268SVivek Gautam * @dev: Device that uses the nvmem device. 59629143268SVivek Gautam * @dev_name: name of the requested nvmem device. 597e2a5402eSSrinivas Kandagatla * 598e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device 599e2a5402eSSrinivas Kandagatla * on success. 600e2a5402eSSrinivas Kandagatla */ 601e2a5402eSSrinivas Kandagatla struct nvmem_device *nvmem_device_get(struct device *dev, const char *dev_name) 602e2a5402eSSrinivas Kandagatla { 603e2a5402eSSrinivas Kandagatla if (dev->of_node) { /* try dt first */ 604e2a5402eSSrinivas Kandagatla struct nvmem_device *nvmem; 605e2a5402eSSrinivas Kandagatla 606e2a5402eSSrinivas Kandagatla nvmem = of_nvmem_device_get(dev->of_node, dev_name); 607e2a5402eSSrinivas Kandagatla 608e2a5402eSSrinivas Kandagatla if (!IS_ERR(nvmem) || PTR_ERR(nvmem) == -EPROBE_DEFER) 609e2a5402eSSrinivas Kandagatla return nvmem; 610e2a5402eSSrinivas Kandagatla 611e2a5402eSSrinivas Kandagatla } 612e2a5402eSSrinivas Kandagatla 6138c2a2b8cSThomas Bogendoerfer return __nvmem_device_get((void *)dev_name, device_match_name); 614e2a5402eSSrinivas Kandagatla } 615e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_get); 616e2a5402eSSrinivas Kandagatla 6178c2a2b8cSThomas Bogendoerfer /** 6188c2a2b8cSThomas Bogendoerfer * nvmem_device_find() - Find nvmem device with matching function 6198c2a2b8cSThomas Bogendoerfer * 6208c2a2b8cSThomas Bogendoerfer * @data: Data to pass to match function 6218c2a2b8cSThomas Bogendoerfer * @match: Callback function to check device 6228c2a2b8cSThomas Bogendoerfer * 6238c2a2b8cSThomas Bogendoerfer * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device 6248c2a2b8cSThomas Bogendoerfer * on success. 6258c2a2b8cSThomas Bogendoerfer */ 6268c2a2b8cSThomas Bogendoerfer struct nvmem_device *nvmem_device_find(void *data, 6278c2a2b8cSThomas Bogendoerfer int (*match)(struct device *dev, const void *data)) 6288c2a2b8cSThomas Bogendoerfer { 6298c2a2b8cSThomas Bogendoerfer return __nvmem_device_get(data, match); 6308c2a2b8cSThomas Bogendoerfer } 6318c2a2b8cSThomas Bogendoerfer EXPORT_SYMBOL_GPL(nvmem_device_find); 6328c2a2b8cSThomas Bogendoerfer 633e2a5402eSSrinivas Kandagatla static int devm_nvmem_device_match(struct device *dev, void *res, void *data) 634e2a5402eSSrinivas Kandagatla { 635e2a5402eSSrinivas Kandagatla struct nvmem_device **nvmem = res; 636e2a5402eSSrinivas Kandagatla 637e2a5402eSSrinivas Kandagatla if (WARN_ON(!nvmem || !*nvmem)) 638e2a5402eSSrinivas Kandagatla return 0; 639e2a5402eSSrinivas Kandagatla 640e2a5402eSSrinivas Kandagatla return *nvmem == data; 641e2a5402eSSrinivas Kandagatla } 642e2a5402eSSrinivas Kandagatla 643e2a5402eSSrinivas Kandagatla static void devm_nvmem_device_release(struct device *dev, void *res) 644e2a5402eSSrinivas Kandagatla { 645e2a5402eSSrinivas Kandagatla nvmem_device_put(*(struct nvmem_device **)res); 646e2a5402eSSrinivas Kandagatla } 647e2a5402eSSrinivas Kandagatla 648e2a5402eSSrinivas Kandagatla /** 649e2a5402eSSrinivas Kandagatla * devm_nvmem_device_put() - put alredy got nvmem device 650e2a5402eSSrinivas Kandagatla * 65129143268SVivek Gautam * @dev: Device that uses the nvmem device. 652e2a5402eSSrinivas Kandagatla * @nvmem: pointer to nvmem device allocated by devm_nvmem_cell_get(), 653e2a5402eSSrinivas Kandagatla * that needs to be released. 654e2a5402eSSrinivas Kandagatla */ 655e2a5402eSSrinivas Kandagatla void devm_nvmem_device_put(struct device *dev, struct nvmem_device *nvmem) 656e2a5402eSSrinivas Kandagatla { 657e2a5402eSSrinivas Kandagatla int ret; 658e2a5402eSSrinivas Kandagatla 659e2a5402eSSrinivas Kandagatla ret = devres_release(dev, devm_nvmem_device_release, 660e2a5402eSSrinivas Kandagatla devm_nvmem_device_match, nvmem); 661e2a5402eSSrinivas Kandagatla 662e2a5402eSSrinivas Kandagatla WARN_ON(ret); 663e2a5402eSSrinivas Kandagatla } 664e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_device_put); 665e2a5402eSSrinivas Kandagatla 666e2a5402eSSrinivas Kandagatla /** 667e2a5402eSSrinivas Kandagatla * nvmem_device_put() - put alredy got nvmem device 668e2a5402eSSrinivas Kandagatla * 669e2a5402eSSrinivas Kandagatla * @nvmem: pointer to nvmem device that needs to be released. 670e2a5402eSSrinivas Kandagatla */ 671e2a5402eSSrinivas Kandagatla void nvmem_device_put(struct nvmem_device *nvmem) 672e2a5402eSSrinivas Kandagatla { 673e2a5402eSSrinivas Kandagatla __nvmem_device_put(nvmem); 674e2a5402eSSrinivas Kandagatla } 675e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_put); 676e2a5402eSSrinivas Kandagatla 677e2a5402eSSrinivas Kandagatla /** 678e2a5402eSSrinivas Kandagatla * devm_nvmem_device_get() - Get nvmem cell of device form a given id 679e2a5402eSSrinivas Kandagatla * 68029143268SVivek Gautam * @dev: Device that requests the nvmem device. 68129143268SVivek Gautam * @id: name id for the requested nvmem device. 682e2a5402eSSrinivas Kandagatla * 683e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_cell 684e2a5402eSSrinivas Kandagatla * on success. The nvmem_cell will be freed by the automatically once the 685e2a5402eSSrinivas Kandagatla * device is freed. 686e2a5402eSSrinivas Kandagatla */ 687e2a5402eSSrinivas Kandagatla struct nvmem_device *devm_nvmem_device_get(struct device *dev, const char *id) 688e2a5402eSSrinivas Kandagatla { 689e2a5402eSSrinivas Kandagatla struct nvmem_device **ptr, *nvmem; 690e2a5402eSSrinivas Kandagatla 691e2a5402eSSrinivas Kandagatla ptr = devres_alloc(devm_nvmem_device_release, sizeof(*ptr), GFP_KERNEL); 692e2a5402eSSrinivas Kandagatla if (!ptr) 693e2a5402eSSrinivas Kandagatla return ERR_PTR(-ENOMEM); 694e2a5402eSSrinivas Kandagatla 695e2a5402eSSrinivas Kandagatla nvmem = nvmem_device_get(dev, id); 696e2a5402eSSrinivas Kandagatla if (!IS_ERR(nvmem)) { 697e2a5402eSSrinivas Kandagatla *ptr = nvmem; 698e2a5402eSSrinivas Kandagatla devres_add(dev, ptr); 699e2a5402eSSrinivas Kandagatla } else { 700e2a5402eSSrinivas Kandagatla devres_free(ptr); 701e2a5402eSSrinivas Kandagatla } 702e2a5402eSSrinivas Kandagatla 703e2a5402eSSrinivas Kandagatla return nvmem; 704e2a5402eSSrinivas Kandagatla } 705e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_device_get); 706e2a5402eSSrinivas Kandagatla 707506157beSBartosz Golaszewski static struct nvmem_cell * 708506157beSBartosz Golaszewski nvmem_cell_get_from_lookup(struct device *dev, const char *con_id) 70969aba794SSrinivas Kandagatla { 710506157beSBartosz Golaszewski struct nvmem_cell *cell = ERR_PTR(-ENOENT); 711506157beSBartosz Golaszewski struct nvmem_cell_lookup *lookup; 71269aba794SSrinivas Kandagatla struct nvmem_device *nvmem; 713506157beSBartosz Golaszewski const char *dev_id; 71469aba794SSrinivas Kandagatla 715506157beSBartosz Golaszewski if (!dev) 716506157beSBartosz Golaszewski return ERR_PTR(-EINVAL); 71769aba794SSrinivas Kandagatla 718506157beSBartosz Golaszewski dev_id = dev_name(dev); 719506157beSBartosz Golaszewski 720506157beSBartosz Golaszewski mutex_lock(&nvmem_lookup_mutex); 721506157beSBartosz Golaszewski 722506157beSBartosz Golaszewski list_for_each_entry(lookup, &nvmem_lookup_list, node) { 723506157beSBartosz Golaszewski if ((strcmp(lookup->dev_id, dev_id) == 0) && 724506157beSBartosz Golaszewski (strcmp(lookup->con_id, con_id) == 0)) { 725506157beSBartosz Golaszewski /* This is the right entry. */ 7268c2a2b8cSThomas Bogendoerfer nvmem = __nvmem_device_get((void *)lookup->nvmem_name, 7278c2a2b8cSThomas Bogendoerfer device_match_name); 728cccb3b19SBartosz Golaszewski if (IS_ERR(nvmem)) { 729506157beSBartosz Golaszewski /* Provider may not be registered yet. */ 730cccb3b19SBartosz Golaszewski cell = ERR_CAST(nvmem); 7319bfd8198SAlban Bedel break; 732506157beSBartosz Golaszewski } 733506157beSBartosz Golaszewski 734506157beSBartosz Golaszewski cell = nvmem_find_cell_by_name(nvmem, 735506157beSBartosz Golaszewski lookup->cell_name); 736506157beSBartosz Golaszewski if (!cell) { 737506157beSBartosz Golaszewski __nvmem_device_put(nvmem); 738cccb3b19SBartosz Golaszewski cell = ERR_PTR(-ENOENT); 739506157beSBartosz Golaszewski } 7409bfd8198SAlban Bedel break; 741506157beSBartosz Golaszewski } 742506157beSBartosz Golaszewski } 743506157beSBartosz Golaszewski 744506157beSBartosz Golaszewski mutex_unlock(&nvmem_lookup_mutex); 74569aba794SSrinivas Kandagatla return cell; 74669aba794SSrinivas Kandagatla } 74769aba794SSrinivas Kandagatla 748e701c67cSMasahiro Yamada #if IS_ENABLED(CONFIG_OF) 7493c53e235SArnd Bergmann static struct nvmem_cell * 7500749aa25SSrinivas Kandagatla nvmem_find_cell_by_node(struct nvmem_device *nvmem, struct device_node *np) 7513c53e235SArnd Bergmann { 7521c832674SAlban Bedel struct nvmem_cell *iter, *cell = NULL; 7533c53e235SArnd Bergmann 7543c53e235SArnd Bergmann mutex_lock(&nvmem_mutex); 7551c832674SAlban Bedel list_for_each_entry(iter, &nvmem->cells, node) { 7561c832674SAlban Bedel if (np == iter->np) { 7571c832674SAlban Bedel cell = iter; 7583c53e235SArnd Bergmann break; 7593c53e235SArnd Bergmann } 7601c832674SAlban Bedel } 7613c53e235SArnd Bergmann mutex_unlock(&nvmem_mutex); 7623c53e235SArnd Bergmann 7633c53e235SArnd Bergmann return cell; 7643c53e235SArnd Bergmann } 7653c53e235SArnd Bergmann 76669aba794SSrinivas Kandagatla /** 76769aba794SSrinivas Kandagatla * of_nvmem_cell_get() - Get a nvmem cell from given device node and cell id 76869aba794SSrinivas Kandagatla * 76929143268SVivek Gautam * @np: Device tree node that uses the nvmem cell. 770165589f0SBartosz Golaszewski * @id: nvmem cell name from nvmem-cell-names property, or NULL 771fd0c478cSVivek Gautam * for the cell at index 0 (the lone cell with no accompanying 772fd0c478cSVivek Gautam * nvmem-cell-names property). 77369aba794SSrinivas Kandagatla * 77469aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 77569aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 77669aba794SSrinivas Kandagatla * nvmem_cell_put(). 77769aba794SSrinivas Kandagatla */ 778165589f0SBartosz Golaszewski struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *id) 77969aba794SSrinivas Kandagatla { 78069aba794SSrinivas Kandagatla struct device_node *cell_np, *nvmem_np; 78169aba794SSrinivas Kandagatla struct nvmem_device *nvmem; 782e888d445SBartosz Golaszewski struct nvmem_cell *cell; 783fd0c478cSVivek Gautam int index = 0; 78469aba794SSrinivas Kandagatla 785fd0c478cSVivek Gautam /* if cell name exists, find index to the name */ 786165589f0SBartosz Golaszewski if (id) 787165589f0SBartosz Golaszewski index = of_property_match_string(np, "nvmem-cell-names", id); 78869aba794SSrinivas Kandagatla 78969aba794SSrinivas Kandagatla cell_np = of_parse_phandle(np, "nvmem-cells", index); 79069aba794SSrinivas Kandagatla if (!cell_np) 7915087cc19SAlban Bedel return ERR_PTR(-ENOENT); 79269aba794SSrinivas Kandagatla 79369aba794SSrinivas Kandagatla nvmem_np = of_get_next_parent(cell_np); 79469aba794SSrinivas Kandagatla if (!nvmem_np) 79569aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 79669aba794SSrinivas Kandagatla 7978c2a2b8cSThomas Bogendoerfer nvmem = __nvmem_device_get(nvmem_np, device_match_of_node); 798aad8d097SMasahiro Yamada of_node_put(nvmem_np); 79969aba794SSrinivas Kandagatla if (IS_ERR(nvmem)) 80069aba794SSrinivas Kandagatla return ERR_CAST(nvmem); 80169aba794SSrinivas Kandagatla 8020749aa25SSrinivas Kandagatla cell = nvmem_find_cell_by_node(nvmem, cell_np); 80369aba794SSrinivas Kandagatla if (!cell) { 804e888d445SBartosz Golaszewski __nvmem_device_put(nvmem); 805e888d445SBartosz Golaszewski return ERR_PTR(-ENOENT); 80669aba794SSrinivas Kandagatla } 80769aba794SSrinivas Kandagatla 80869aba794SSrinivas Kandagatla return cell; 80969aba794SSrinivas Kandagatla } 81069aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_nvmem_cell_get); 81169aba794SSrinivas Kandagatla #endif 81269aba794SSrinivas Kandagatla 81369aba794SSrinivas Kandagatla /** 81469aba794SSrinivas Kandagatla * nvmem_cell_get() - Get nvmem cell of device form a given cell name 81569aba794SSrinivas Kandagatla * 81629143268SVivek Gautam * @dev: Device that requests the nvmem cell. 817165589f0SBartosz Golaszewski * @id: nvmem cell name to get (this corresponds with the name from the 818165589f0SBartosz Golaszewski * nvmem-cell-names property for DT systems and with the con_id from 819165589f0SBartosz Golaszewski * the lookup entry for non-DT systems). 82069aba794SSrinivas Kandagatla * 82169aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 82269aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 82369aba794SSrinivas Kandagatla * nvmem_cell_put(). 82469aba794SSrinivas Kandagatla */ 825165589f0SBartosz Golaszewski struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *id) 82669aba794SSrinivas Kandagatla { 82769aba794SSrinivas Kandagatla struct nvmem_cell *cell; 82869aba794SSrinivas Kandagatla 82969aba794SSrinivas Kandagatla if (dev->of_node) { /* try dt first */ 830165589f0SBartosz Golaszewski cell = of_nvmem_cell_get(dev->of_node, id); 83169aba794SSrinivas Kandagatla if (!IS_ERR(cell) || PTR_ERR(cell) == -EPROBE_DEFER) 83269aba794SSrinivas Kandagatla return cell; 83369aba794SSrinivas Kandagatla } 83469aba794SSrinivas Kandagatla 835165589f0SBartosz Golaszewski /* NULL cell id only allowed for device tree; invalid otherwise */ 836165589f0SBartosz Golaszewski if (!id) 83787ed1405SDouglas Anderson return ERR_PTR(-EINVAL); 83887ed1405SDouglas Anderson 839165589f0SBartosz Golaszewski return nvmem_cell_get_from_lookup(dev, id); 84069aba794SSrinivas Kandagatla } 84169aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_get); 84269aba794SSrinivas Kandagatla 84369aba794SSrinivas Kandagatla static void devm_nvmem_cell_release(struct device *dev, void *res) 84469aba794SSrinivas Kandagatla { 84569aba794SSrinivas Kandagatla nvmem_cell_put(*(struct nvmem_cell **)res); 84669aba794SSrinivas Kandagatla } 84769aba794SSrinivas Kandagatla 84869aba794SSrinivas Kandagatla /** 84969aba794SSrinivas Kandagatla * devm_nvmem_cell_get() - Get nvmem cell of device form a given id 85069aba794SSrinivas Kandagatla * 85129143268SVivek Gautam * @dev: Device that requests the nvmem cell. 85229143268SVivek Gautam * @id: nvmem cell name id to get. 85369aba794SSrinivas Kandagatla * 85469aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 85569aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 85669aba794SSrinivas Kandagatla * automatically once the device is freed. 85769aba794SSrinivas Kandagatla */ 85869aba794SSrinivas Kandagatla struct nvmem_cell *devm_nvmem_cell_get(struct device *dev, const char *id) 85969aba794SSrinivas Kandagatla { 86069aba794SSrinivas Kandagatla struct nvmem_cell **ptr, *cell; 86169aba794SSrinivas Kandagatla 86269aba794SSrinivas Kandagatla ptr = devres_alloc(devm_nvmem_cell_release, sizeof(*ptr), GFP_KERNEL); 86369aba794SSrinivas Kandagatla if (!ptr) 86469aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 86569aba794SSrinivas Kandagatla 86669aba794SSrinivas Kandagatla cell = nvmem_cell_get(dev, id); 86769aba794SSrinivas Kandagatla if (!IS_ERR(cell)) { 86869aba794SSrinivas Kandagatla *ptr = cell; 86969aba794SSrinivas Kandagatla devres_add(dev, ptr); 87069aba794SSrinivas Kandagatla } else { 87169aba794SSrinivas Kandagatla devres_free(ptr); 87269aba794SSrinivas Kandagatla } 87369aba794SSrinivas Kandagatla 87469aba794SSrinivas Kandagatla return cell; 87569aba794SSrinivas Kandagatla } 87669aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_cell_get); 87769aba794SSrinivas Kandagatla 87869aba794SSrinivas Kandagatla static int devm_nvmem_cell_match(struct device *dev, void *res, void *data) 87969aba794SSrinivas Kandagatla { 88069aba794SSrinivas Kandagatla struct nvmem_cell **c = res; 88169aba794SSrinivas Kandagatla 88269aba794SSrinivas Kandagatla if (WARN_ON(!c || !*c)) 88369aba794SSrinivas Kandagatla return 0; 88469aba794SSrinivas Kandagatla 88569aba794SSrinivas Kandagatla return *c == data; 88669aba794SSrinivas Kandagatla } 88769aba794SSrinivas Kandagatla 88869aba794SSrinivas Kandagatla /** 88969aba794SSrinivas Kandagatla * devm_nvmem_cell_put() - Release previously allocated nvmem cell 89069aba794SSrinivas Kandagatla * from devm_nvmem_cell_get. 89169aba794SSrinivas Kandagatla * 89229143268SVivek Gautam * @dev: Device that requests the nvmem cell. 89329143268SVivek Gautam * @cell: Previously allocated nvmem cell by devm_nvmem_cell_get(). 89469aba794SSrinivas Kandagatla */ 89569aba794SSrinivas Kandagatla void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell) 89669aba794SSrinivas Kandagatla { 89769aba794SSrinivas Kandagatla int ret; 89869aba794SSrinivas Kandagatla 89969aba794SSrinivas Kandagatla ret = devres_release(dev, devm_nvmem_cell_release, 90069aba794SSrinivas Kandagatla devm_nvmem_cell_match, cell); 90169aba794SSrinivas Kandagatla 90269aba794SSrinivas Kandagatla WARN_ON(ret); 90369aba794SSrinivas Kandagatla } 90469aba794SSrinivas Kandagatla EXPORT_SYMBOL(devm_nvmem_cell_put); 90569aba794SSrinivas Kandagatla 90669aba794SSrinivas Kandagatla /** 90769aba794SSrinivas Kandagatla * nvmem_cell_put() - Release previously allocated nvmem cell. 90869aba794SSrinivas Kandagatla * 90929143268SVivek Gautam * @cell: Previously allocated nvmem cell by nvmem_cell_get(). 91069aba794SSrinivas Kandagatla */ 91169aba794SSrinivas Kandagatla void nvmem_cell_put(struct nvmem_cell *cell) 91269aba794SSrinivas Kandagatla { 91369aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 91469aba794SSrinivas Kandagatla 91569aba794SSrinivas Kandagatla __nvmem_device_put(nvmem); 91669aba794SSrinivas Kandagatla } 91769aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_put); 91869aba794SSrinivas Kandagatla 919f7c04f16SMasahiro Yamada static void nvmem_shift_read_buffer_in_place(struct nvmem_cell *cell, void *buf) 92069aba794SSrinivas Kandagatla { 92169aba794SSrinivas Kandagatla u8 *p, *b; 9222fe518feSJorge Ramirez-Ortiz int i, extra, bit_offset = cell->bit_offset; 92369aba794SSrinivas Kandagatla 92469aba794SSrinivas Kandagatla p = b = buf; 92569aba794SSrinivas Kandagatla if (bit_offset) { 92669aba794SSrinivas Kandagatla /* First shift */ 92769aba794SSrinivas Kandagatla *b++ >>= bit_offset; 92869aba794SSrinivas Kandagatla 92969aba794SSrinivas Kandagatla /* setup rest of the bytes if any */ 93069aba794SSrinivas Kandagatla for (i = 1; i < cell->bytes; i++) { 93169aba794SSrinivas Kandagatla /* Get bits from next byte and shift them towards msb */ 93269aba794SSrinivas Kandagatla *p |= *b << (BITS_PER_BYTE - bit_offset); 93369aba794SSrinivas Kandagatla 93469aba794SSrinivas Kandagatla p = b; 93569aba794SSrinivas Kandagatla *b++ >>= bit_offset; 93669aba794SSrinivas Kandagatla } 9372fe518feSJorge Ramirez-Ortiz } else { 9382fe518feSJorge Ramirez-Ortiz /* point to the msb */ 9392fe518feSJorge Ramirez-Ortiz p += cell->bytes - 1; 9402fe518feSJorge Ramirez-Ortiz } 94169aba794SSrinivas Kandagatla 94269aba794SSrinivas Kandagatla /* result fits in less bytes */ 9432fe518feSJorge Ramirez-Ortiz extra = cell->bytes - DIV_ROUND_UP(cell->nbits, BITS_PER_BYTE); 9442fe518feSJorge Ramirez-Ortiz while (--extra >= 0) 94569aba794SSrinivas Kandagatla *p-- = 0; 9462fe518feSJorge Ramirez-Ortiz 94769aba794SSrinivas Kandagatla /* clear msb bits if any leftover in the last byte */ 94869aba794SSrinivas Kandagatla *p &= GENMASK((cell->nbits%BITS_PER_BYTE) - 1, 0); 94969aba794SSrinivas Kandagatla } 95069aba794SSrinivas Kandagatla 95169aba794SSrinivas Kandagatla static int __nvmem_cell_read(struct nvmem_device *nvmem, 95269aba794SSrinivas Kandagatla struct nvmem_cell *cell, 95369aba794SSrinivas Kandagatla void *buf, size_t *len) 95469aba794SSrinivas Kandagatla { 95569aba794SSrinivas Kandagatla int rc; 95669aba794SSrinivas Kandagatla 957795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, cell->offset, buf, cell->bytes); 95869aba794SSrinivas Kandagatla 959287980e4SArnd Bergmann if (rc) 96069aba794SSrinivas Kandagatla return rc; 96169aba794SSrinivas Kandagatla 96269aba794SSrinivas Kandagatla /* shift bits in-place */ 963cbf854abSAxel Lin if (cell->bit_offset || cell->nbits) 96469aba794SSrinivas Kandagatla nvmem_shift_read_buffer_in_place(cell, buf); 96569aba794SSrinivas Kandagatla 9663b4a6877SVivek Gautam if (len) 96769aba794SSrinivas Kandagatla *len = cell->bytes; 96869aba794SSrinivas Kandagatla 96969aba794SSrinivas Kandagatla return 0; 97069aba794SSrinivas Kandagatla } 97169aba794SSrinivas Kandagatla 97269aba794SSrinivas Kandagatla /** 97369aba794SSrinivas Kandagatla * nvmem_cell_read() - Read a given nvmem cell 97469aba794SSrinivas Kandagatla * 97569aba794SSrinivas Kandagatla * @cell: nvmem cell to be read. 9763b4a6877SVivek Gautam * @len: pointer to length of cell which will be populated on successful read; 9773b4a6877SVivek Gautam * can be NULL. 97869aba794SSrinivas Kandagatla * 979b577fafcSBrian Norris * Return: ERR_PTR() on error or a valid pointer to a buffer on success. The 980b577fafcSBrian Norris * buffer should be freed by the consumer with a kfree(). 98169aba794SSrinivas Kandagatla */ 98269aba794SSrinivas Kandagatla void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len) 98369aba794SSrinivas Kandagatla { 98469aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 98569aba794SSrinivas Kandagatla u8 *buf; 98669aba794SSrinivas Kandagatla int rc; 98769aba794SSrinivas Kandagatla 988795ddd18SSrinivas Kandagatla if (!nvmem) 98969aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 99069aba794SSrinivas Kandagatla 99169aba794SSrinivas Kandagatla buf = kzalloc(cell->bytes, GFP_KERNEL); 99269aba794SSrinivas Kandagatla if (!buf) 99369aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 99469aba794SSrinivas Kandagatla 99569aba794SSrinivas Kandagatla rc = __nvmem_cell_read(nvmem, cell, buf, len); 996287980e4SArnd Bergmann if (rc) { 99769aba794SSrinivas Kandagatla kfree(buf); 99869aba794SSrinivas Kandagatla return ERR_PTR(rc); 99969aba794SSrinivas Kandagatla } 100069aba794SSrinivas Kandagatla 100169aba794SSrinivas Kandagatla return buf; 100269aba794SSrinivas Kandagatla } 100369aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_read); 100469aba794SSrinivas Kandagatla 1005f7c04f16SMasahiro Yamada static void *nvmem_cell_prepare_write_buffer(struct nvmem_cell *cell, 100669aba794SSrinivas Kandagatla u8 *_buf, int len) 100769aba794SSrinivas Kandagatla { 100869aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 100969aba794SSrinivas Kandagatla int i, rc, nbits, bit_offset = cell->bit_offset; 101069aba794SSrinivas Kandagatla u8 v, *p, *buf, *b, pbyte, pbits; 101169aba794SSrinivas Kandagatla 101269aba794SSrinivas Kandagatla nbits = cell->nbits; 101369aba794SSrinivas Kandagatla buf = kzalloc(cell->bytes, GFP_KERNEL); 101469aba794SSrinivas Kandagatla if (!buf) 101569aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 101669aba794SSrinivas Kandagatla 101769aba794SSrinivas Kandagatla memcpy(buf, _buf, len); 101869aba794SSrinivas Kandagatla p = b = buf; 101969aba794SSrinivas Kandagatla 102069aba794SSrinivas Kandagatla if (bit_offset) { 102169aba794SSrinivas Kandagatla pbyte = *b; 102269aba794SSrinivas Kandagatla *b <<= bit_offset; 102369aba794SSrinivas Kandagatla 102469aba794SSrinivas Kandagatla /* setup the first byte with lsb bits from nvmem */ 1025795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, cell->offset, &v, 1); 102650808bfcSMathieu Malaterre if (rc) 102750808bfcSMathieu Malaterre goto err; 102869aba794SSrinivas Kandagatla *b++ |= GENMASK(bit_offset - 1, 0) & v; 102969aba794SSrinivas Kandagatla 103069aba794SSrinivas Kandagatla /* setup rest of the byte if any */ 103169aba794SSrinivas Kandagatla for (i = 1; i < cell->bytes; i++) { 103269aba794SSrinivas Kandagatla /* Get last byte bits and shift them towards lsb */ 103369aba794SSrinivas Kandagatla pbits = pbyte >> (BITS_PER_BYTE - 1 - bit_offset); 103469aba794SSrinivas Kandagatla pbyte = *b; 103569aba794SSrinivas Kandagatla p = b; 103669aba794SSrinivas Kandagatla *b <<= bit_offset; 103769aba794SSrinivas Kandagatla *b++ |= pbits; 103869aba794SSrinivas Kandagatla } 103969aba794SSrinivas Kandagatla } 104069aba794SSrinivas Kandagatla 104169aba794SSrinivas Kandagatla /* if it's not end on byte boundary */ 104269aba794SSrinivas Kandagatla if ((nbits + bit_offset) % BITS_PER_BYTE) { 104369aba794SSrinivas Kandagatla /* setup the last byte with msb bits from nvmem */ 1044795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, 104569aba794SSrinivas Kandagatla cell->offset + cell->bytes - 1, &v, 1); 104650808bfcSMathieu Malaterre if (rc) 104750808bfcSMathieu Malaterre goto err; 104869aba794SSrinivas Kandagatla *p |= GENMASK(7, (nbits + bit_offset) % BITS_PER_BYTE) & v; 104969aba794SSrinivas Kandagatla 105069aba794SSrinivas Kandagatla } 105169aba794SSrinivas Kandagatla 105269aba794SSrinivas Kandagatla return buf; 105350808bfcSMathieu Malaterre err: 105450808bfcSMathieu Malaterre kfree(buf); 105550808bfcSMathieu Malaterre return ERR_PTR(rc); 105669aba794SSrinivas Kandagatla } 105769aba794SSrinivas Kandagatla 105869aba794SSrinivas Kandagatla /** 105969aba794SSrinivas Kandagatla * nvmem_cell_write() - Write to a given nvmem cell 106069aba794SSrinivas Kandagatla * 106169aba794SSrinivas Kandagatla * @cell: nvmem cell to be written. 106269aba794SSrinivas Kandagatla * @buf: Buffer to be written. 106369aba794SSrinivas Kandagatla * @len: length of buffer to be written to nvmem cell. 106469aba794SSrinivas Kandagatla * 106569aba794SSrinivas Kandagatla * Return: length of bytes written or negative on failure. 106669aba794SSrinivas Kandagatla */ 106769aba794SSrinivas Kandagatla int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len) 106869aba794SSrinivas Kandagatla { 106969aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 107069aba794SSrinivas Kandagatla int rc; 107169aba794SSrinivas Kandagatla 1072795ddd18SSrinivas Kandagatla if (!nvmem || nvmem->read_only || 107369aba794SSrinivas Kandagatla (cell->bit_offset == 0 && len != cell->bytes)) 107469aba794SSrinivas Kandagatla return -EINVAL; 107569aba794SSrinivas Kandagatla 107669aba794SSrinivas Kandagatla if (cell->bit_offset || cell->nbits) { 107769aba794SSrinivas Kandagatla buf = nvmem_cell_prepare_write_buffer(cell, buf, len); 107869aba794SSrinivas Kandagatla if (IS_ERR(buf)) 107969aba794SSrinivas Kandagatla return PTR_ERR(buf); 108069aba794SSrinivas Kandagatla } 108169aba794SSrinivas Kandagatla 1082795ddd18SSrinivas Kandagatla rc = nvmem_reg_write(nvmem, cell->offset, buf, cell->bytes); 108369aba794SSrinivas Kandagatla 108469aba794SSrinivas Kandagatla /* free the tmp buffer */ 1085ace22170SAxel Lin if (cell->bit_offset || cell->nbits) 108669aba794SSrinivas Kandagatla kfree(buf); 108769aba794SSrinivas Kandagatla 1088287980e4SArnd Bergmann if (rc) 108969aba794SSrinivas Kandagatla return rc; 109069aba794SSrinivas Kandagatla 109169aba794SSrinivas Kandagatla return len; 109269aba794SSrinivas Kandagatla } 109369aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_write); 109469aba794SSrinivas Kandagatla 10956bb317ceSYangtao Li static int nvmem_cell_read_common(struct device *dev, const char *cell_id, 10966bb317ceSYangtao Li void *val, size_t count) 10970a9b2d1cSFabrice Gasnier { 10980a9b2d1cSFabrice Gasnier struct nvmem_cell *cell; 10990a9b2d1cSFabrice Gasnier void *buf; 11000a9b2d1cSFabrice Gasnier size_t len; 11010a9b2d1cSFabrice Gasnier 11020a9b2d1cSFabrice Gasnier cell = nvmem_cell_get(dev, cell_id); 11030a9b2d1cSFabrice Gasnier if (IS_ERR(cell)) 11040a9b2d1cSFabrice Gasnier return PTR_ERR(cell); 11050a9b2d1cSFabrice Gasnier 11060a9b2d1cSFabrice Gasnier buf = nvmem_cell_read(cell, &len); 11070a9b2d1cSFabrice Gasnier if (IS_ERR(buf)) { 11080a9b2d1cSFabrice Gasnier nvmem_cell_put(cell); 11090a9b2d1cSFabrice Gasnier return PTR_ERR(buf); 11100a9b2d1cSFabrice Gasnier } 11116bb317ceSYangtao Li if (len != count) { 11120a9b2d1cSFabrice Gasnier kfree(buf); 11130a9b2d1cSFabrice Gasnier nvmem_cell_put(cell); 11140a9b2d1cSFabrice Gasnier return -EINVAL; 11150a9b2d1cSFabrice Gasnier } 11166bb317ceSYangtao Li memcpy(val, buf, count); 11170a9b2d1cSFabrice Gasnier kfree(buf); 11180a9b2d1cSFabrice Gasnier nvmem_cell_put(cell); 11190a9b2d1cSFabrice Gasnier 11200a9b2d1cSFabrice Gasnier return 0; 11210a9b2d1cSFabrice Gasnier } 11226bb317ceSYangtao Li 11236bb317ceSYangtao Li /** 11246bb317ceSYangtao Li * nvmem_cell_read_u16() - Read a cell value as an u16 11256bb317ceSYangtao Li * 11266bb317ceSYangtao Li * @dev: Device that requests the nvmem cell. 11276bb317ceSYangtao Li * @cell_id: Name of nvmem cell to read. 11286bb317ceSYangtao Li * @val: pointer to output value. 11296bb317ceSYangtao Li * 11306bb317ceSYangtao Li * Return: 0 on success or negative errno. 11316bb317ceSYangtao Li */ 11326bb317ceSYangtao Li int nvmem_cell_read_u16(struct device *dev, const char *cell_id, u16 *val) 11336bb317ceSYangtao Li { 11346bb317ceSYangtao Li return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val)); 11356bb317ceSYangtao Li } 11360a9b2d1cSFabrice Gasnier EXPORT_SYMBOL_GPL(nvmem_cell_read_u16); 11370a9b2d1cSFabrice Gasnier 11380a9b2d1cSFabrice Gasnier /** 1139d026d70aSLeonard Crestez * nvmem_cell_read_u32() - Read a cell value as an u32 1140d026d70aSLeonard Crestez * 1141d026d70aSLeonard Crestez * @dev: Device that requests the nvmem cell. 1142d026d70aSLeonard Crestez * @cell_id: Name of nvmem cell to read. 1143d026d70aSLeonard Crestez * @val: pointer to output value. 1144d026d70aSLeonard Crestez * 1145d026d70aSLeonard Crestez * Return: 0 on success or negative errno. 1146d026d70aSLeonard Crestez */ 1147d026d70aSLeonard Crestez int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val) 1148d026d70aSLeonard Crestez { 11496bb317ceSYangtao Li return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val)); 1150d026d70aSLeonard Crestez } 1151d026d70aSLeonard Crestez EXPORT_SYMBOL_GPL(nvmem_cell_read_u32); 1152d026d70aSLeonard Crestez 1153d026d70aSLeonard Crestez /** 11548b977c54SYangtao Li * nvmem_cell_read_u64() - Read a cell value as an u64 11558b977c54SYangtao Li * 11568b977c54SYangtao Li * @dev: Device that requests the nvmem cell. 11578b977c54SYangtao Li * @cell_id: Name of nvmem cell to read. 11588b977c54SYangtao Li * @val: pointer to output value. 11598b977c54SYangtao Li * 11608b977c54SYangtao Li * Return: 0 on success or negative errno. 11618b977c54SYangtao Li */ 11628b977c54SYangtao Li int nvmem_cell_read_u64(struct device *dev, const char *cell_id, u64 *val) 11638b977c54SYangtao Li { 11648b977c54SYangtao Li return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val)); 11658b977c54SYangtao Li } 11668b977c54SYangtao Li EXPORT_SYMBOL_GPL(nvmem_cell_read_u64); 11678b977c54SYangtao Li 11688b977c54SYangtao Li /** 1169e2a5402eSSrinivas Kandagatla * nvmem_device_cell_read() - Read a given nvmem device and cell 1170e2a5402eSSrinivas Kandagatla * 1171e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to read from. 1172e2a5402eSSrinivas Kandagatla * @info: nvmem cell info to be read. 1173e2a5402eSSrinivas Kandagatla * @buf: buffer pointer which will be populated on successful read. 1174e2a5402eSSrinivas Kandagatla * 1175e2a5402eSSrinivas Kandagatla * Return: length of successful bytes read on success and negative 1176e2a5402eSSrinivas Kandagatla * error code on error. 1177e2a5402eSSrinivas Kandagatla */ 1178e2a5402eSSrinivas Kandagatla ssize_t nvmem_device_cell_read(struct nvmem_device *nvmem, 1179e2a5402eSSrinivas Kandagatla struct nvmem_cell_info *info, void *buf) 1180e2a5402eSSrinivas Kandagatla { 1181e2a5402eSSrinivas Kandagatla struct nvmem_cell cell; 1182e2a5402eSSrinivas Kandagatla int rc; 1183e2a5402eSSrinivas Kandagatla ssize_t len; 1184e2a5402eSSrinivas Kandagatla 1185795ddd18SSrinivas Kandagatla if (!nvmem) 1186e2a5402eSSrinivas Kandagatla return -EINVAL; 1187e2a5402eSSrinivas Kandagatla 1188e2a5402eSSrinivas Kandagatla rc = nvmem_cell_info_to_nvmem_cell(nvmem, info, &cell); 1189287980e4SArnd Bergmann if (rc) 1190e2a5402eSSrinivas Kandagatla return rc; 1191e2a5402eSSrinivas Kandagatla 1192e2a5402eSSrinivas Kandagatla rc = __nvmem_cell_read(nvmem, &cell, buf, &len); 1193287980e4SArnd Bergmann if (rc) 1194e2a5402eSSrinivas Kandagatla return rc; 1195e2a5402eSSrinivas Kandagatla 1196e2a5402eSSrinivas Kandagatla return len; 1197e2a5402eSSrinivas Kandagatla } 1198e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_cell_read); 1199e2a5402eSSrinivas Kandagatla 1200e2a5402eSSrinivas Kandagatla /** 1201e2a5402eSSrinivas Kandagatla * nvmem_device_cell_write() - Write cell to a given nvmem device 1202e2a5402eSSrinivas Kandagatla * 1203e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to be written to. 120429143268SVivek Gautam * @info: nvmem cell info to be written. 1205e2a5402eSSrinivas Kandagatla * @buf: buffer to be written to cell. 1206e2a5402eSSrinivas Kandagatla * 1207e2a5402eSSrinivas Kandagatla * Return: length of bytes written or negative error code on failure. 120848f63a2cSBartosz Golaszewski */ 1209e2a5402eSSrinivas Kandagatla int nvmem_device_cell_write(struct nvmem_device *nvmem, 1210e2a5402eSSrinivas Kandagatla struct nvmem_cell_info *info, void *buf) 1211e2a5402eSSrinivas Kandagatla { 1212e2a5402eSSrinivas Kandagatla struct nvmem_cell cell; 1213e2a5402eSSrinivas Kandagatla int rc; 1214e2a5402eSSrinivas Kandagatla 1215795ddd18SSrinivas Kandagatla if (!nvmem) 1216e2a5402eSSrinivas Kandagatla return -EINVAL; 1217e2a5402eSSrinivas Kandagatla 1218e2a5402eSSrinivas Kandagatla rc = nvmem_cell_info_to_nvmem_cell(nvmem, info, &cell); 1219287980e4SArnd Bergmann if (rc) 1220e2a5402eSSrinivas Kandagatla return rc; 1221e2a5402eSSrinivas Kandagatla 1222e2a5402eSSrinivas Kandagatla return nvmem_cell_write(&cell, buf, cell.bytes); 1223e2a5402eSSrinivas Kandagatla } 1224e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_cell_write); 1225e2a5402eSSrinivas Kandagatla 1226e2a5402eSSrinivas Kandagatla /** 1227e2a5402eSSrinivas Kandagatla * nvmem_device_read() - Read from a given nvmem device 1228e2a5402eSSrinivas Kandagatla * 1229e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to read from. 1230e2a5402eSSrinivas Kandagatla * @offset: offset in nvmem device. 1231e2a5402eSSrinivas Kandagatla * @bytes: number of bytes to read. 1232e2a5402eSSrinivas Kandagatla * @buf: buffer pointer which will be populated on successful read. 1233e2a5402eSSrinivas Kandagatla * 1234e2a5402eSSrinivas Kandagatla * Return: length of successful bytes read on success and negative 1235e2a5402eSSrinivas Kandagatla * error code on error. 1236e2a5402eSSrinivas Kandagatla */ 1237e2a5402eSSrinivas Kandagatla int nvmem_device_read(struct nvmem_device *nvmem, 1238e2a5402eSSrinivas Kandagatla unsigned int offset, 1239e2a5402eSSrinivas Kandagatla size_t bytes, void *buf) 1240e2a5402eSSrinivas Kandagatla { 1241e2a5402eSSrinivas Kandagatla int rc; 1242e2a5402eSSrinivas Kandagatla 1243795ddd18SSrinivas Kandagatla if (!nvmem) 1244e2a5402eSSrinivas Kandagatla return -EINVAL; 1245e2a5402eSSrinivas Kandagatla 1246795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, offset, buf, bytes); 1247e2a5402eSSrinivas Kandagatla 1248287980e4SArnd Bergmann if (rc) 1249e2a5402eSSrinivas Kandagatla return rc; 1250e2a5402eSSrinivas Kandagatla 1251e2a5402eSSrinivas Kandagatla return bytes; 1252e2a5402eSSrinivas Kandagatla } 1253e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_read); 1254e2a5402eSSrinivas Kandagatla 1255e2a5402eSSrinivas Kandagatla /** 1256e2a5402eSSrinivas Kandagatla * nvmem_device_write() - Write cell to a given nvmem device 1257e2a5402eSSrinivas Kandagatla * 1258e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to be written to. 1259e2a5402eSSrinivas Kandagatla * @offset: offset in nvmem device. 1260e2a5402eSSrinivas Kandagatla * @bytes: number of bytes to write. 1261e2a5402eSSrinivas Kandagatla * @buf: buffer to be written. 1262e2a5402eSSrinivas Kandagatla * 1263e2a5402eSSrinivas Kandagatla * Return: length of bytes written or negative error code on failure. 126448f63a2cSBartosz Golaszewski */ 1265e2a5402eSSrinivas Kandagatla int nvmem_device_write(struct nvmem_device *nvmem, 1266e2a5402eSSrinivas Kandagatla unsigned int offset, 1267e2a5402eSSrinivas Kandagatla size_t bytes, void *buf) 1268e2a5402eSSrinivas Kandagatla { 1269e2a5402eSSrinivas Kandagatla int rc; 1270e2a5402eSSrinivas Kandagatla 1271795ddd18SSrinivas Kandagatla if (!nvmem) 1272e2a5402eSSrinivas Kandagatla return -EINVAL; 1273e2a5402eSSrinivas Kandagatla 1274795ddd18SSrinivas Kandagatla rc = nvmem_reg_write(nvmem, offset, buf, bytes); 1275e2a5402eSSrinivas Kandagatla 1276287980e4SArnd Bergmann if (rc) 1277e2a5402eSSrinivas Kandagatla return rc; 1278e2a5402eSSrinivas Kandagatla 1279e2a5402eSSrinivas Kandagatla 1280e2a5402eSSrinivas Kandagatla return bytes; 1281e2a5402eSSrinivas Kandagatla } 1282e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_write); 1283e2a5402eSSrinivas Kandagatla 1284d7b9fd16SBartosz Golaszewski /** 1285b985f4cbSBartosz Golaszewski * nvmem_add_cell_table() - register a table of cell info entries 1286b985f4cbSBartosz Golaszewski * 1287b985f4cbSBartosz Golaszewski * @table: table of cell info entries 1288b985f4cbSBartosz Golaszewski */ 1289b985f4cbSBartosz Golaszewski void nvmem_add_cell_table(struct nvmem_cell_table *table) 1290b985f4cbSBartosz Golaszewski { 1291b985f4cbSBartosz Golaszewski mutex_lock(&nvmem_cell_mutex); 1292b985f4cbSBartosz Golaszewski list_add_tail(&table->node, &nvmem_cell_tables); 1293b985f4cbSBartosz Golaszewski mutex_unlock(&nvmem_cell_mutex); 1294b985f4cbSBartosz Golaszewski } 1295b985f4cbSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_add_cell_table); 1296b985f4cbSBartosz Golaszewski 1297b985f4cbSBartosz Golaszewski /** 1298b985f4cbSBartosz Golaszewski * nvmem_del_cell_table() - remove a previously registered cell info table 1299b985f4cbSBartosz Golaszewski * 1300b985f4cbSBartosz Golaszewski * @table: table of cell info entries 1301b985f4cbSBartosz Golaszewski */ 1302b985f4cbSBartosz Golaszewski void nvmem_del_cell_table(struct nvmem_cell_table *table) 1303b985f4cbSBartosz Golaszewski { 1304b985f4cbSBartosz Golaszewski mutex_lock(&nvmem_cell_mutex); 1305b985f4cbSBartosz Golaszewski list_del(&table->node); 1306b985f4cbSBartosz Golaszewski mutex_unlock(&nvmem_cell_mutex); 1307b985f4cbSBartosz Golaszewski } 1308b985f4cbSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_del_cell_table); 1309b985f4cbSBartosz Golaszewski 1310b985f4cbSBartosz Golaszewski /** 1311506157beSBartosz Golaszewski * nvmem_add_cell_lookups() - register a list of cell lookup entries 1312506157beSBartosz Golaszewski * 1313506157beSBartosz Golaszewski * @entries: array of cell lookup entries 1314506157beSBartosz Golaszewski * @nentries: number of cell lookup entries in the array 1315506157beSBartosz Golaszewski */ 1316506157beSBartosz Golaszewski void nvmem_add_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries) 1317506157beSBartosz Golaszewski { 1318506157beSBartosz Golaszewski int i; 1319506157beSBartosz Golaszewski 1320506157beSBartosz Golaszewski mutex_lock(&nvmem_lookup_mutex); 1321506157beSBartosz Golaszewski for (i = 0; i < nentries; i++) 1322506157beSBartosz Golaszewski list_add_tail(&entries[i].node, &nvmem_lookup_list); 1323506157beSBartosz Golaszewski mutex_unlock(&nvmem_lookup_mutex); 1324506157beSBartosz Golaszewski } 1325506157beSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_add_cell_lookups); 1326506157beSBartosz Golaszewski 1327506157beSBartosz Golaszewski /** 1328506157beSBartosz Golaszewski * nvmem_del_cell_lookups() - remove a list of previously added cell lookup 1329506157beSBartosz Golaszewski * entries 1330506157beSBartosz Golaszewski * 1331506157beSBartosz Golaszewski * @entries: array of cell lookup entries 1332506157beSBartosz Golaszewski * @nentries: number of cell lookup entries in the array 1333506157beSBartosz Golaszewski */ 1334506157beSBartosz Golaszewski void nvmem_del_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries) 1335506157beSBartosz Golaszewski { 1336506157beSBartosz Golaszewski int i; 1337506157beSBartosz Golaszewski 1338506157beSBartosz Golaszewski mutex_lock(&nvmem_lookup_mutex); 1339506157beSBartosz Golaszewski for (i = 0; i < nentries; i++) 1340506157beSBartosz Golaszewski list_del(&entries[i].node); 1341506157beSBartosz Golaszewski mutex_unlock(&nvmem_lookup_mutex); 1342506157beSBartosz Golaszewski } 1343506157beSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_del_cell_lookups); 1344506157beSBartosz Golaszewski 1345506157beSBartosz Golaszewski /** 1346d7b9fd16SBartosz Golaszewski * nvmem_dev_name() - Get the name of a given nvmem device. 1347d7b9fd16SBartosz Golaszewski * 1348d7b9fd16SBartosz Golaszewski * @nvmem: nvmem device. 1349d7b9fd16SBartosz Golaszewski * 1350d7b9fd16SBartosz Golaszewski * Return: name of the nvmem device. 1351d7b9fd16SBartosz Golaszewski */ 1352d7b9fd16SBartosz Golaszewski const char *nvmem_dev_name(struct nvmem_device *nvmem) 1353d7b9fd16SBartosz Golaszewski { 1354d7b9fd16SBartosz Golaszewski return dev_name(&nvmem->dev); 1355d7b9fd16SBartosz Golaszewski } 1356d7b9fd16SBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_dev_name); 1357d7b9fd16SBartosz Golaszewski 1358eace75cfSSrinivas Kandagatla static int __init nvmem_init(void) 1359eace75cfSSrinivas Kandagatla { 1360eace75cfSSrinivas Kandagatla return bus_register(&nvmem_bus_type); 1361eace75cfSSrinivas Kandagatla } 1362eace75cfSSrinivas Kandagatla 1363eace75cfSSrinivas Kandagatla static void __exit nvmem_exit(void) 1364eace75cfSSrinivas Kandagatla { 1365eace75cfSSrinivas Kandagatla bus_unregister(&nvmem_bus_type); 1366eace75cfSSrinivas Kandagatla } 1367eace75cfSSrinivas Kandagatla 1368eace75cfSSrinivas Kandagatla subsys_initcall(nvmem_init); 1369eace75cfSSrinivas Kandagatla module_exit(nvmem_exit); 1370eace75cfSSrinivas Kandagatla 1371eace75cfSSrinivas Kandagatla MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org"); 1372eace75cfSSrinivas Kandagatla MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com"); 1373eace75cfSSrinivas Kandagatla MODULE_DESCRIPTION("nvmem Driver Core"); 1374eace75cfSSrinivas Kandagatla MODULE_LICENSE("GPL v2"); 1375