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); 75a9c3766cSKhouloud Touil gpiod_put(nvmem->wp_gpio); 76eace75cfSSrinivas Kandagatla kfree(nvmem); 77eace75cfSSrinivas Kandagatla } 78eace75cfSSrinivas Kandagatla 79eace75cfSSrinivas Kandagatla static const struct device_type nvmem_provider_type = { 80eace75cfSSrinivas Kandagatla .release = nvmem_release, 81eace75cfSSrinivas Kandagatla }; 82eace75cfSSrinivas Kandagatla 83eace75cfSSrinivas Kandagatla static struct bus_type nvmem_bus_type = { 84eace75cfSSrinivas Kandagatla .name = "nvmem", 85eace75cfSSrinivas Kandagatla }; 86eace75cfSSrinivas Kandagatla 87eace75cfSSrinivas Kandagatla static void nvmem_cell_drop(struct nvmem_cell *cell) 88eace75cfSSrinivas Kandagatla { 89bee1138bSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_REMOVE, cell); 90c7235ee3SBartosz Golaszewski mutex_lock(&nvmem_mutex); 91eace75cfSSrinivas Kandagatla list_del(&cell->node); 92c7235ee3SBartosz Golaszewski mutex_unlock(&nvmem_mutex); 930749aa25SSrinivas Kandagatla of_node_put(cell->np); 9416bb7abcSBitan Biswas kfree_const(cell->name); 95eace75cfSSrinivas Kandagatla kfree(cell); 96eace75cfSSrinivas Kandagatla } 97eace75cfSSrinivas Kandagatla 98eace75cfSSrinivas Kandagatla static void nvmem_device_remove_all_cells(const struct nvmem_device *nvmem) 99eace75cfSSrinivas Kandagatla { 1001852183eSBartosz Golaszewski struct nvmem_cell *cell, *p; 101eace75cfSSrinivas Kandagatla 102c7235ee3SBartosz Golaszewski list_for_each_entry_safe(cell, p, &nvmem->cells, node) 103eace75cfSSrinivas Kandagatla nvmem_cell_drop(cell); 104eace75cfSSrinivas Kandagatla } 105eace75cfSSrinivas Kandagatla 106eace75cfSSrinivas Kandagatla static void nvmem_cell_add(struct nvmem_cell *cell) 107eace75cfSSrinivas Kandagatla { 108c7235ee3SBartosz Golaszewski mutex_lock(&nvmem_mutex); 109c7235ee3SBartosz Golaszewski list_add_tail(&cell->node, &cell->nvmem->cells); 110c7235ee3SBartosz Golaszewski mutex_unlock(&nvmem_mutex); 111bee1138bSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_ADD, cell); 112eace75cfSSrinivas Kandagatla } 113eace75cfSSrinivas Kandagatla 114eace75cfSSrinivas Kandagatla static int nvmem_cell_info_to_nvmem_cell(struct nvmem_device *nvmem, 115eace75cfSSrinivas Kandagatla const struct nvmem_cell_info *info, 116eace75cfSSrinivas Kandagatla struct nvmem_cell *cell) 117eace75cfSSrinivas Kandagatla { 118eace75cfSSrinivas Kandagatla cell->nvmem = nvmem; 119eace75cfSSrinivas Kandagatla cell->offset = info->offset; 120eace75cfSSrinivas Kandagatla cell->bytes = info->bytes; 12116bb7abcSBitan Biswas cell->name = kstrdup_const(info->name, GFP_KERNEL); 12216bb7abcSBitan Biswas if (!cell->name) 12316bb7abcSBitan Biswas return -ENOMEM; 124eace75cfSSrinivas Kandagatla 125eace75cfSSrinivas Kandagatla cell->bit_offset = info->bit_offset; 126eace75cfSSrinivas Kandagatla cell->nbits = info->nbits; 127eace75cfSSrinivas Kandagatla 128eace75cfSSrinivas Kandagatla if (cell->nbits) 129eace75cfSSrinivas Kandagatla cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset, 130eace75cfSSrinivas Kandagatla BITS_PER_BYTE); 131eace75cfSSrinivas Kandagatla 132eace75cfSSrinivas Kandagatla if (!IS_ALIGNED(cell->offset, nvmem->stride)) { 133eace75cfSSrinivas Kandagatla dev_err(&nvmem->dev, 134eace75cfSSrinivas Kandagatla "cell %s unaligned to nvmem stride %d\n", 135eace75cfSSrinivas Kandagatla cell->name, nvmem->stride); 136eace75cfSSrinivas Kandagatla return -EINVAL; 137eace75cfSSrinivas Kandagatla } 138eace75cfSSrinivas Kandagatla 139eace75cfSSrinivas Kandagatla return 0; 140eace75cfSSrinivas Kandagatla } 141eace75cfSSrinivas Kandagatla 142b3db17e4SAndrew Lunn /** 143b3db17e4SAndrew Lunn * nvmem_add_cells() - Add cell information to an nvmem device 144b3db17e4SAndrew Lunn * 145b3db17e4SAndrew Lunn * @nvmem: nvmem device to add cells to. 146b3db17e4SAndrew Lunn * @info: nvmem cell info to add to the device 147b3db17e4SAndrew Lunn * @ncells: number of cells in info 148b3db17e4SAndrew Lunn * 149b3db17e4SAndrew Lunn * Return: 0 or negative error code on failure. 150b3db17e4SAndrew Lunn */ 151ef92ab30SSrinivas Kandagatla static int nvmem_add_cells(struct nvmem_device *nvmem, 152b3db17e4SAndrew Lunn const struct nvmem_cell_info *info, 153b3db17e4SAndrew Lunn int ncells) 154eace75cfSSrinivas Kandagatla { 155eace75cfSSrinivas Kandagatla struct nvmem_cell **cells; 156eace75cfSSrinivas Kandagatla int i, rval; 157eace75cfSSrinivas Kandagatla 158b3db17e4SAndrew Lunn cells = kcalloc(ncells, sizeof(*cells), GFP_KERNEL); 159eace75cfSSrinivas Kandagatla if (!cells) 160eace75cfSSrinivas Kandagatla return -ENOMEM; 161eace75cfSSrinivas Kandagatla 162b3db17e4SAndrew Lunn for (i = 0; i < ncells; i++) { 163eace75cfSSrinivas Kandagatla cells[i] = kzalloc(sizeof(**cells), GFP_KERNEL); 164eace75cfSSrinivas Kandagatla if (!cells[i]) { 165eace75cfSSrinivas Kandagatla rval = -ENOMEM; 166eace75cfSSrinivas Kandagatla goto err; 167eace75cfSSrinivas Kandagatla } 168eace75cfSSrinivas Kandagatla 169eace75cfSSrinivas Kandagatla rval = nvmem_cell_info_to_nvmem_cell(nvmem, &info[i], cells[i]); 170287980e4SArnd Bergmann if (rval) { 171eace75cfSSrinivas Kandagatla kfree(cells[i]); 172eace75cfSSrinivas Kandagatla goto err; 173eace75cfSSrinivas Kandagatla } 174eace75cfSSrinivas Kandagatla 175eace75cfSSrinivas Kandagatla nvmem_cell_add(cells[i]); 176eace75cfSSrinivas Kandagatla } 177eace75cfSSrinivas Kandagatla 178eace75cfSSrinivas Kandagatla /* remove tmp array */ 179eace75cfSSrinivas Kandagatla kfree(cells); 180eace75cfSSrinivas Kandagatla 181eace75cfSSrinivas Kandagatla return 0; 182eace75cfSSrinivas Kandagatla err: 183dfdf1414SRasmus Villemoes while (i--) 184eace75cfSSrinivas Kandagatla nvmem_cell_drop(cells[i]); 185eace75cfSSrinivas Kandagatla 186dfdf1414SRasmus Villemoes kfree(cells); 187dfdf1414SRasmus Villemoes 188eace75cfSSrinivas Kandagatla return rval; 189eace75cfSSrinivas Kandagatla } 190eace75cfSSrinivas Kandagatla 191bee1138bSBartosz Golaszewski /** 192bee1138bSBartosz Golaszewski * nvmem_register_notifier() - Register a notifier block for nvmem events. 193bee1138bSBartosz Golaszewski * 194bee1138bSBartosz Golaszewski * @nb: notifier block to be called on nvmem events. 195bee1138bSBartosz Golaszewski * 196bee1138bSBartosz Golaszewski * Return: 0 on success, negative error number on failure. 197bee1138bSBartosz Golaszewski */ 198bee1138bSBartosz Golaszewski int nvmem_register_notifier(struct notifier_block *nb) 199bee1138bSBartosz Golaszewski { 200bee1138bSBartosz Golaszewski return blocking_notifier_chain_register(&nvmem_notifier, nb); 201bee1138bSBartosz Golaszewski } 202bee1138bSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_register_notifier); 203bee1138bSBartosz Golaszewski 204bee1138bSBartosz Golaszewski /** 205bee1138bSBartosz Golaszewski * nvmem_unregister_notifier() - Unregister a notifier block for nvmem events. 206bee1138bSBartosz Golaszewski * 207bee1138bSBartosz Golaszewski * @nb: notifier block to be unregistered. 208bee1138bSBartosz Golaszewski * 209bee1138bSBartosz Golaszewski * Return: 0 on success, negative error number on failure. 210bee1138bSBartosz Golaszewski */ 211bee1138bSBartosz Golaszewski int nvmem_unregister_notifier(struct notifier_block *nb) 212bee1138bSBartosz Golaszewski { 213bee1138bSBartosz Golaszewski return blocking_notifier_chain_unregister(&nvmem_notifier, nb); 214bee1138bSBartosz Golaszewski } 215bee1138bSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_unregister_notifier); 216bee1138bSBartosz Golaszewski 217b985f4cbSBartosz Golaszewski static int nvmem_add_cells_from_table(struct nvmem_device *nvmem) 218b985f4cbSBartosz Golaszewski { 219b985f4cbSBartosz Golaszewski const struct nvmem_cell_info *info; 220b985f4cbSBartosz Golaszewski struct nvmem_cell_table *table; 221b985f4cbSBartosz Golaszewski struct nvmem_cell *cell; 222b985f4cbSBartosz Golaszewski int rval = 0, i; 223b985f4cbSBartosz Golaszewski 224b985f4cbSBartosz Golaszewski mutex_lock(&nvmem_cell_mutex); 225b985f4cbSBartosz Golaszewski list_for_each_entry(table, &nvmem_cell_tables, node) { 226b985f4cbSBartosz Golaszewski if (strcmp(nvmem_dev_name(nvmem), table->nvmem_name) == 0) { 227b985f4cbSBartosz Golaszewski for (i = 0; i < table->ncells; i++) { 228b985f4cbSBartosz Golaszewski info = &table->cells[i]; 229b985f4cbSBartosz Golaszewski 230b985f4cbSBartosz Golaszewski cell = kzalloc(sizeof(*cell), GFP_KERNEL); 231b985f4cbSBartosz Golaszewski if (!cell) { 232b985f4cbSBartosz Golaszewski rval = -ENOMEM; 233b985f4cbSBartosz Golaszewski goto out; 234b985f4cbSBartosz Golaszewski } 235b985f4cbSBartosz Golaszewski 236b985f4cbSBartosz Golaszewski rval = nvmem_cell_info_to_nvmem_cell(nvmem, 237b985f4cbSBartosz Golaszewski info, 238b985f4cbSBartosz Golaszewski cell); 239b985f4cbSBartosz Golaszewski if (rval) { 240b985f4cbSBartosz Golaszewski kfree(cell); 241b985f4cbSBartosz Golaszewski goto out; 242b985f4cbSBartosz Golaszewski } 243b985f4cbSBartosz Golaszewski 244b985f4cbSBartosz Golaszewski nvmem_cell_add(cell); 245b985f4cbSBartosz Golaszewski } 246b985f4cbSBartosz Golaszewski } 247b985f4cbSBartosz Golaszewski } 248b985f4cbSBartosz Golaszewski 249b985f4cbSBartosz Golaszewski out: 250b985f4cbSBartosz Golaszewski mutex_unlock(&nvmem_cell_mutex); 251b985f4cbSBartosz Golaszewski return rval; 252b985f4cbSBartosz Golaszewski } 253b985f4cbSBartosz Golaszewski 254e888d445SBartosz Golaszewski static struct nvmem_cell * 255506157beSBartosz Golaszewski nvmem_find_cell_by_name(struct nvmem_device *nvmem, const char *cell_id) 256506157beSBartosz Golaszewski { 2571c832674SAlban Bedel struct nvmem_cell *iter, *cell = NULL; 258506157beSBartosz Golaszewski 259506157beSBartosz Golaszewski mutex_lock(&nvmem_mutex); 2601c832674SAlban Bedel list_for_each_entry(iter, &nvmem->cells, node) { 2611c832674SAlban Bedel if (strcmp(cell_id, iter->name) == 0) { 2621c832674SAlban Bedel cell = iter; 263506157beSBartosz Golaszewski break; 264506157beSBartosz Golaszewski } 2651c832674SAlban Bedel } 266506157beSBartosz Golaszewski mutex_unlock(&nvmem_mutex); 267506157beSBartosz Golaszewski 268506157beSBartosz Golaszewski return cell; 269506157beSBartosz Golaszewski } 270506157beSBartosz Golaszewski 271e888d445SBartosz Golaszewski static int nvmem_add_cells_from_of(struct nvmem_device *nvmem) 272e888d445SBartosz Golaszewski { 273e888d445SBartosz Golaszewski struct device_node *parent, *child; 274e888d445SBartosz Golaszewski struct device *dev = &nvmem->dev; 275e888d445SBartosz Golaszewski struct nvmem_cell *cell; 276e888d445SBartosz Golaszewski const __be32 *addr; 277e888d445SBartosz Golaszewski int len; 278e888d445SBartosz Golaszewski 279e888d445SBartosz Golaszewski parent = dev->of_node; 280e888d445SBartosz Golaszewski 281e888d445SBartosz Golaszewski for_each_child_of_node(parent, child) { 282e888d445SBartosz Golaszewski addr = of_get_property(child, "reg", &len); 283e888d445SBartosz Golaszewski if (!addr || (len < 2 * sizeof(u32))) { 284e888d445SBartosz Golaszewski dev_err(dev, "nvmem: invalid reg on %pOF\n", child); 285e888d445SBartosz Golaszewski return -EINVAL; 286e888d445SBartosz Golaszewski } 287e888d445SBartosz Golaszewski 288e888d445SBartosz Golaszewski cell = kzalloc(sizeof(*cell), GFP_KERNEL); 289e888d445SBartosz Golaszewski if (!cell) 290e888d445SBartosz Golaszewski return -ENOMEM; 291e888d445SBartosz Golaszewski 292e888d445SBartosz Golaszewski cell->nvmem = nvmem; 2930749aa25SSrinivas Kandagatla cell->np = of_node_get(child); 294e888d445SBartosz Golaszewski cell->offset = be32_to_cpup(addr++); 295e888d445SBartosz Golaszewski cell->bytes = be32_to_cpup(addr); 296badcdff1SRob Herring cell->name = kasprintf(GFP_KERNEL, "%pOFn", child); 297e888d445SBartosz Golaszewski 298e888d445SBartosz Golaszewski addr = of_get_property(child, "bits", &len); 299e888d445SBartosz Golaszewski if (addr && len == (2 * sizeof(u32))) { 300e888d445SBartosz Golaszewski cell->bit_offset = be32_to_cpup(addr++); 301e888d445SBartosz Golaszewski cell->nbits = be32_to_cpup(addr); 302e888d445SBartosz Golaszewski } 303e888d445SBartosz Golaszewski 304e888d445SBartosz Golaszewski if (cell->nbits) 305e888d445SBartosz Golaszewski cell->bytes = DIV_ROUND_UP( 306e888d445SBartosz Golaszewski cell->nbits + cell->bit_offset, 307e888d445SBartosz Golaszewski BITS_PER_BYTE); 308e888d445SBartosz Golaszewski 309e888d445SBartosz Golaszewski if (!IS_ALIGNED(cell->offset, nvmem->stride)) { 310e888d445SBartosz Golaszewski dev_err(dev, "cell %s unaligned to nvmem stride %d\n", 311e888d445SBartosz Golaszewski cell->name, nvmem->stride); 312e888d445SBartosz Golaszewski /* Cells already added will be freed later. */ 31316bb7abcSBitan Biswas kfree_const(cell->name); 314e888d445SBartosz Golaszewski kfree(cell); 315e888d445SBartosz Golaszewski return -EINVAL; 316e888d445SBartosz Golaszewski } 317e888d445SBartosz Golaszewski 318e888d445SBartosz Golaszewski nvmem_cell_add(cell); 319e888d445SBartosz Golaszewski } 320e888d445SBartosz Golaszewski 321e888d445SBartosz Golaszewski return 0; 322e888d445SBartosz Golaszewski } 323e888d445SBartosz Golaszewski 324eace75cfSSrinivas Kandagatla /** 325eace75cfSSrinivas Kandagatla * nvmem_register() - Register a nvmem device for given nvmem_config. 326eace75cfSSrinivas Kandagatla * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem 327eace75cfSSrinivas Kandagatla * 328eace75cfSSrinivas Kandagatla * @config: nvmem device configuration with which nvmem device is created. 329eace75cfSSrinivas Kandagatla * 330eace75cfSSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device 331eace75cfSSrinivas Kandagatla * on success. 332eace75cfSSrinivas Kandagatla */ 333eace75cfSSrinivas Kandagatla 334eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem_register(const struct nvmem_config *config) 335eace75cfSSrinivas Kandagatla { 336eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem; 337eace75cfSSrinivas Kandagatla int rval; 338eace75cfSSrinivas Kandagatla 339eace75cfSSrinivas Kandagatla if (!config->dev) 340eace75cfSSrinivas Kandagatla return ERR_PTR(-EINVAL); 341eace75cfSSrinivas Kandagatla 342061a320bSSrinivas Kandagatla if (!config->reg_read && !config->reg_write) 343061a320bSSrinivas Kandagatla return ERR_PTR(-EINVAL); 344061a320bSSrinivas Kandagatla 345eace75cfSSrinivas Kandagatla nvmem = kzalloc(sizeof(*nvmem), GFP_KERNEL); 346eace75cfSSrinivas Kandagatla if (!nvmem) 347eace75cfSSrinivas Kandagatla return ERR_PTR(-ENOMEM); 348eace75cfSSrinivas Kandagatla 349eace75cfSSrinivas Kandagatla rval = ida_simple_get(&nvmem_ida, 0, 0, GFP_KERNEL); 350eace75cfSSrinivas Kandagatla if (rval < 0) { 351eace75cfSSrinivas Kandagatla kfree(nvmem); 352eace75cfSSrinivas Kandagatla return ERR_PTR(rval); 353eace75cfSSrinivas Kandagatla } 35431c6ff51SBartosz Golaszewski 3552a127da4SKhouloud Touil if (config->wp_gpio) 3562a127da4SKhouloud Touil nvmem->wp_gpio = config->wp_gpio; 3572a127da4SKhouloud Touil else 3582a127da4SKhouloud Touil nvmem->wp_gpio = gpiod_get_optional(config->dev, "wp", 3592a127da4SKhouloud Touil GPIOD_OUT_HIGH); 360f7d8d7dcSBartosz Golaszewski if (IS_ERR(nvmem->wp_gpio)) { 361f7d8d7dcSBartosz Golaszewski ida_simple_remove(&nvmem_ida, nvmem->id); 362f7d8d7dcSBartosz Golaszewski rval = PTR_ERR(nvmem->wp_gpio); 363f7d8d7dcSBartosz Golaszewski kfree(nvmem); 364f7d8d7dcSBartosz Golaszewski return ERR_PTR(rval); 365f7d8d7dcSBartosz Golaszewski } 3662a127da4SKhouloud Touil 367c1de7f43SBartosz Golaszewski kref_init(&nvmem->refcnt); 368c7235ee3SBartosz Golaszewski INIT_LIST_HEAD(&nvmem->cells); 369c1de7f43SBartosz Golaszewski 370eace75cfSSrinivas Kandagatla nvmem->id = rval; 371eace75cfSSrinivas Kandagatla nvmem->owner = config->owner; 37217eb18d6SMasahiro Yamada if (!nvmem->owner && config->dev->driver) 37317eb18d6SMasahiro Yamada nvmem->owner = config->dev->driver->owner; 37499897efdSHeiner Kallweit nvmem->stride = config->stride ?: 1; 37599897efdSHeiner Kallweit nvmem->word_size = config->word_size ?: 1; 376795ddd18SSrinivas Kandagatla nvmem->size = config->size; 377eace75cfSSrinivas Kandagatla nvmem->dev.type = &nvmem_provider_type; 378eace75cfSSrinivas Kandagatla nvmem->dev.bus = &nvmem_bus_type; 379eace75cfSSrinivas Kandagatla nvmem->dev.parent = config->dev; 380e6de179dSSrinivas Kandagatla nvmem->root_only = config->root_only; 381795ddd18SSrinivas Kandagatla nvmem->priv = config->priv; 38216688453SAlexandre Belloni nvmem->type = config->type; 383795ddd18SSrinivas Kandagatla nvmem->reg_read = config->reg_read; 384795ddd18SSrinivas Kandagatla nvmem->reg_write = config->reg_write; 385517f14d9SBartosz Golaszewski if (!config->no_of_node) 386fc2f9970SHeiner Kallweit nvmem->dev.of_node = config->dev->of_node; 387fd0f4906SAndrey Smirnov 388fd0f4906SAndrey Smirnov if (config->id == -1 && config->name) { 389fd0f4906SAndrey Smirnov dev_set_name(&nvmem->dev, "%s", config->name); 390fd0f4906SAndrey Smirnov } else { 391eace75cfSSrinivas Kandagatla dev_set_name(&nvmem->dev, "%s%d", 3925253193dSAban Bedel config->name ? : "nvmem", 3935253193dSAban Bedel config->name ? config->id : nvmem->id); 394fd0f4906SAndrey Smirnov } 395eace75cfSSrinivas Kandagatla 3961716cfe8SAlban Bedel nvmem->read_only = device_property_present(config->dev, "read-only") || 3971716cfe8SAlban Bedel config->read_only || !nvmem->reg_write; 398eace75cfSSrinivas Kandagatla 399ae0c2d72SSrinivas Kandagatla nvmem->dev.groups = nvmem_sysfs_get_groups(nvmem, config); 400eace75cfSSrinivas Kandagatla 401eace75cfSSrinivas Kandagatla dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name); 402eace75cfSSrinivas Kandagatla 403*f60442ddSSrinivas Kandagatla rval = device_register(&nvmem->dev); 404b6c217abSAndrew Lunn if (rval) 4053360acdfSJohan Hovold goto err_put_device; 406b6c217abSAndrew Lunn 407b6c217abSAndrew Lunn if (config->compat) { 408ae0c2d72SSrinivas Kandagatla rval = nvmem_sysfs_setup_compat(nvmem, config); 409b6c217abSAndrew Lunn if (rval) 4103360acdfSJohan Hovold goto err_device_del; 411eace75cfSSrinivas Kandagatla } 412eace75cfSSrinivas Kandagatla 413fa72d847SBartosz Golaszewski if (config->cells) { 414fa72d847SBartosz Golaszewski rval = nvmem_add_cells(nvmem, config->cells, config->ncells); 415fa72d847SBartosz Golaszewski if (rval) 416fa72d847SBartosz Golaszewski goto err_teardown_compat; 417fa72d847SBartosz Golaszewski } 418eace75cfSSrinivas Kandagatla 419b985f4cbSBartosz Golaszewski rval = nvmem_add_cells_from_table(nvmem); 420b985f4cbSBartosz Golaszewski if (rval) 421b985f4cbSBartosz Golaszewski goto err_remove_cells; 422b985f4cbSBartosz Golaszewski 423e888d445SBartosz Golaszewski rval = nvmem_add_cells_from_of(nvmem); 424e888d445SBartosz Golaszewski if (rval) 425e888d445SBartosz Golaszewski goto err_remove_cells; 426e888d445SBartosz Golaszewski 427f4853e1cSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_ADD, nvmem); 428bee1138bSBartosz Golaszewski 429eace75cfSSrinivas Kandagatla return nvmem; 4303360acdfSJohan Hovold 431b985f4cbSBartosz Golaszewski err_remove_cells: 432b985f4cbSBartosz Golaszewski nvmem_device_remove_all_cells(nvmem); 433fa72d847SBartosz Golaszewski err_teardown_compat: 434fa72d847SBartosz Golaszewski if (config->compat) 435ae0c2d72SSrinivas Kandagatla nvmem_sysfs_remove_compat(nvmem, config); 4363360acdfSJohan Hovold err_device_del: 4373360acdfSJohan Hovold device_del(&nvmem->dev); 4383360acdfSJohan Hovold err_put_device: 4393360acdfSJohan Hovold put_device(&nvmem->dev); 4403360acdfSJohan Hovold 441b6c217abSAndrew Lunn return ERR_PTR(rval); 442eace75cfSSrinivas Kandagatla } 443eace75cfSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_register); 444eace75cfSSrinivas Kandagatla 445c1de7f43SBartosz Golaszewski static void nvmem_device_release(struct kref *kref) 446c1de7f43SBartosz Golaszewski { 447c1de7f43SBartosz Golaszewski struct nvmem_device *nvmem; 448c1de7f43SBartosz Golaszewski 449c1de7f43SBartosz Golaszewski nvmem = container_of(kref, struct nvmem_device, refcnt); 450c1de7f43SBartosz Golaszewski 451bee1138bSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_REMOVE, nvmem); 452bee1138bSBartosz Golaszewski 453c1de7f43SBartosz Golaszewski if (nvmem->flags & FLAG_COMPAT) 454c1de7f43SBartosz Golaszewski device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); 455c1de7f43SBartosz Golaszewski 456c1de7f43SBartosz Golaszewski nvmem_device_remove_all_cells(nvmem); 457*f60442ddSSrinivas Kandagatla device_unregister(&nvmem->dev); 458c1de7f43SBartosz Golaszewski } 459c1de7f43SBartosz Golaszewski 460eace75cfSSrinivas Kandagatla /** 461eace75cfSSrinivas Kandagatla * nvmem_unregister() - Unregister previously registered nvmem device 462eace75cfSSrinivas Kandagatla * 463eace75cfSSrinivas Kandagatla * @nvmem: Pointer to previously registered nvmem device. 464eace75cfSSrinivas Kandagatla */ 465bf58e882SBartosz Golaszewski void nvmem_unregister(struct nvmem_device *nvmem) 466eace75cfSSrinivas Kandagatla { 467c1de7f43SBartosz Golaszewski kref_put(&nvmem->refcnt, nvmem_device_release); 468eace75cfSSrinivas Kandagatla } 469eace75cfSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_unregister); 470eace75cfSSrinivas Kandagatla 471f1f50ecaSAndrey Smirnov static void devm_nvmem_release(struct device *dev, void *res) 472f1f50ecaSAndrey Smirnov { 473bf58e882SBartosz Golaszewski nvmem_unregister(*(struct nvmem_device **)res); 474f1f50ecaSAndrey Smirnov } 475f1f50ecaSAndrey Smirnov 476f1f50ecaSAndrey Smirnov /** 477f1f50ecaSAndrey Smirnov * devm_nvmem_register() - Register a managed nvmem device for given 478f1f50ecaSAndrey Smirnov * nvmem_config. 479f1f50ecaSAndrey Smirnov * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem 480f1f50ecaSAndrey Smirnov * 481b378c779SSrinivas Kandagatla * @dev: Device that uses the nvmem device. 482f1f50ecaSAndrey Smirnov * @config: nvmem device configuration with which nvmem device is created. 483f1f50ecaSAndrey Smirnov * 484f1f50ecaSAndrey Smirnov * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device 485f1f50ecaSAndrey Smirnov * on success. 486f1f50ecaSAndrey Smirnov */ 487f1f50ecaSAndrey Smirnov struct nvmem_device *devm_nvmem_register(struct device *dev, 488f1f50ecaSAndrey Smirnov const struct nvmem_config *config) 489f1f50ecaSAndrey Smirnov { 490f1f50ecaSAndrey Smirnov struct nvmem_device **ptr, *nvmem; 491f1f50ecaSAndrey Smirnov 492f1f50ecaSAndrey Smirnov ptr = devres_alloc(devm_nvmem_release, sizeof(*ptr), GFP_KERNEL); 493f1f50ecaSAndrey Smirnov if (!ptr) 494f1f50ecaSAndrey Smirnov return ERR_PTR(-ENOMEM); 495f1f50ecaSAndrey Smirnov 496f1f50ecaSAndrey Smirnov nvmem = nvmem_register(config); 497f1f50ecaSAndrey Smirnov 498f1f50ecaSAndrey Smirnov if (!IS_ERR(nvmem)) { 499f1f50ecaSAndrey Smirnov *ptr = nvmem; 500f1f50ecaSAndrey Smirnov devres_add(dev, ptr); 501f1f50ecaSAndrey Smirnov } else { 502f1f50ecaSAndrey Smirnov devres_free(ptr); 503f1f50ecaSAndrey Smirnov } 504f1f50ecaSAndrey Smirnov 505f1f50ecaSAndrey Smirnov return nvmem; 506f1f50ecaSAndrey Smirnov } 507f1f50ecaSAndrey Smirnov EXPORT_SYMBOL_GPL(devm_nvmem_register); 508f1f50ecaSAndrey Smirnov 509f1f50ecaSAndrey Smirnov static int devm_nvmem_match(struct device *dev, void *res, void *data) 510f1f50ecaSAndrey Smirnov { 511f1f50ecaSAndrey Smirnov struct nvmem_device **r = res; 512f1f50ecaSAndrey Smirnov 513f1f50ecaSAndrey Smirnov return *r == data; 514f1f50ecaSAndrey Smirnov } 515f1f50ecaSAndrey Smirnov 516f1f50ecaSAndrey Smirnov /** 517f1f50ecaSAndrey Smirnov * devm_nvmem_unregister() - Unregister previously registered managed nvmem 518f1f50ecaSAndrey Smirnov * device. 519f1f50ecaSAndrey Smirnov * 520b378c779SSrinivas Kandagatla * @dev: Device that uses the nvmem device. 521f1f50ecaSAndrey Smirnov * @nvmem: Pointer to previously registered nvmem device. 522f1f50ecaSAndrey Smirnov * 523f1f50ecaSAndrey Smirnov * Return: Will be an negative on error or a zero on success. 524f1f50ecaSAndrey Smirnov */ 525f1f50ecaSAndrey Smirnov int devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem) 526f1f50ecaSAndrey Smirnov { 527f1f50ecaSAndrey Smirnov return devres_release(dev, devm_nvmem_release, devm_nvmem_match, nvmem); 528f1f50ecaSAndrey Smirnov } 529f1f50ecaSAndrey Smirnov EXPORT_SYMBOL(devm_nvmem_unregister); 530f1f50ecaSAndrey Smirnov 5318c2a2b8cSThomas Bogendoerfer static struct nvmem_device *__nvmem_device_get(void *data, 5328c2a2b8cSThomas Bogendoerfer int (*match)(struct device *dev, const void *data)) 53369aba794SSrinivas Kandagatla { 53469aba794SSrinivas Kandagatla struct nvmem_device *nvmem = NULL; 5358c2a2b8cSThomas Bogendoerfer struct device *dev; 53669aba794SSrinivas Kandagatla 537c7235ee3SBartosz Golaszewski mutex_lock(&nvmem_mutex); 5388c2a2b8cSThomas Bogendoerfer dev = bus_find_device(&nvmem_bus_type, NULL, data, match); 5398c2a2b8cSThomas Bogendoerfer if (dev) 5408c2a2b8cSThomas Bogendoerfer nvmem = to_nvmem_device(dev); 54169aba794SSrinivas Kandagatla mutex_unlock(&nvmem_mutex); 542c7235ee3SBartosz Golaszewski if (!nvmem) 543c7235ee3SBartosz Golaszewski return ERR_PTR(-EPROBE_DEFER); 54469aba794SSrinivas Kandagatla 54569aba794SSrinivas Kandagatla if (!try_module_get(nvmem->owner)) { 54669aba794SSrinivas Kandagatla dev_err(&nvmem->dev, 54769aba794SSrinivas Kandagatla "could not increase module refcount for cell %s\n", 5485db652c9SBartosz Golaszewski nvmem_dev_name(nvmem)); 54969aba794SSrinivas Kandagatla 55073e9dc4dSAlban Bedel put_device(&nvmem->dev); 55169aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 55269aba794SSrinivas Kandagatla } 55369aba794SSrinivas Kandagatla 554c1de7f43SBartosz Golaszewski kref_get(&nvmem->refcnt); 555c1de7f43SBartosz Golaszewski 55669aba794SSrinivas Kandagatla return nvmem; 55769aba794SSrinivas Kandagatla } 55869aba794SSrinivas Kandagatla 55969aba794SSrinivas Kandagatla static void __nvmem_device_put(struct nvmem_device *nvmem) 56069aba794SSrinivas Kandagatla { 56173e9dc4dSAlban Bedel put_device(&nvmem->dev); 56269aba794SSrinivas Kandagatla module_put(nvmem->owner); 563c1de7f43SBartosz Golaszewski kref_put(&nvmem->refcnt, nvmem_device_release); 56469aba794SSrinivas Kandagatla } 56569aba794SSrinivas Kandagatla 566e701c67cSMasahiro Yamada #if IS_ENABLED(CONFIG_OF) 567e2a5402eSSrinivas Kandagatla /** 568e2a5402eSSrinivas Kandagatla * of_nvmem_device_get() - Get nvmem device from a given id 569e2a5402eSSrinivas Kandagatla * 57029143268SVivek Gautam * @np: Device tree node that uses the nvmem device. 571e2a5402eSSrinivas Kandagatla * @id: nvmem name from nvmem-names property. 572e2a5402eSSrinivas Kandagatla * 573e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device 574e2a5402eSSrinivas Kandagatla * on success. 575e2a5402eSSrinivas Kandagatla */ 576e2a5402eSSrinivas Kandagatla struct nvmem_device *of_nvmem_device_get(struct device_node *np, const char *id) 577e2a5402eSSrinivas Kandagatla { 578e2a5402eSSrinivas Kandagatla 579e2a5402eSSrinivas Kandagatla struct device_node *nvmem_np; 580d4e7fef1SAlban Bedel int index = 0; 581e2a5402eSSrinivas Kandagatla 582d4e7fef1SAlban Bedel if (id) 583e2a5402eSSrinivas Kandagatla index = of_property_match_string(np, "nvmem-names", id); 584e2a5402eSSrinivas Kandagatla 585e2a5402eSSrinivas Kandagatla nvmem_np = of_parse_phandle(np, "nvmem", index); 586e2a5402eSSrinivas Kandagatla if (!nvmem_np) 587d4e7fef1SAlban Bedel return ERR_PTR(-ENOENT); 588e2a5402eSSrinivas Kandagatla 5898c2a2b8cSThomas Bogendoerfer return __nvmem_device_get(nvmem_np, device_match_of_node); 590e2a5402eSSrinivas Kandagatla } 591e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_nvmem_device_get); 592e2a5402eSSrinivas Kandagatla #endif 593e2a5402eSSrinivas Kandagatla 594e2a5402eSSrinivas Kandagatla /** 595e2a5402eSSrinivas Kandagatla * nvmem_device_get() - Get nvmem device from a given id 596e2a5402eSSrinivas Kandagatla * 59729143268SVivek Gautam * @dev: Device that uses the nvmem device. 59829143268SVivek Gautam * @dev_name: name of the requested nvmem device. 599e2a5402eSSrinivas Kandagatla * 600e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device 601e2a5402eSSrinivas Kandagatla * on success. 602e2a5402eSSrinivas Kandagatla */ 603e2a5402eSSrinivas Kandagatla struct nvmem_device *nvmem_device_get(struct device *dev, const char *dev_name) 604e2a5402eSSrinivas Kandagatla { 605e2a5402eSSrinivas Kandagatla if (dev->of_node) { /* try dt first */ 606e2a5402eSSrinivas Kandagatla struct nvmem_device *nvmem; 607e2a5402eSSrinivas Kandagatla 608e2a5402eSSrinivas Kandagatla nvmem = of_nvmem_device_get(dev->of_node, dev_name); 609e2a5402eSSrinivas Kandagatla 610e2a5402eSSrinivas Kandagatla if (!IS_ERR(nvmem) || PTR_ERR(nvmem) == -EPROBE_DEFER) 611e2a5402eSSrinivas Kandagatla return nvmem; 612e2a5402eSSrinivas Kandagatla 613e2a5402eSSrinivas Kandagatla } 614e2a5402eSSrinivas Kandagatla 6158c2a2b8cSThomas Bogendoerfer return __nvmem_device_get((void *)dev_name, device_match_name); 616e2a5402eSSrinivas Kandagatla } 617e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_get); 618e2a5402eSSrinivas Kandagatla 6198c2a2b8cSThomas Bogendoerfer /** 6208c2a2b8cSThomas Bogendoerfer * nvmem_device_find() - Find nvmem device with matching function 6218c2a2b8cSThomas Bogendoerfer * 6228c2a2b8cSThomas Bogendoerfer * @data: Data to pass to match function 6238c2a2b8cSThomas Bogendoerfer * @match: Callback function to check device 6248c2a2b8cSThomas Bogendoerfer * 6258c2a2b8cSThomas Bogendoerfer * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device 6268c2a2b8cSThomas Bogendoerfer * on success. 6278c2a2b8cSThomas Bogendoerfer */ 6288c2a2b8cSThomas Bogendoerfer struct nvmem_device *nvmem_device_find(void *data, 6298c2a2b8cSThomas Bogendoerfer int (*match)(struct device *dev, const void *data)) 6308c2a2b8cSThomas Bogendoerfer { 6318c2a2b8cSThomas Bogendoerfer return __nvmem_device_get(data, match); 6328c2a2b8cSThomas Bogendoerfer } 6338c2a2b8cSThomas Bogendoerfer EXPORT_SYMBOL_GPL(nvmem_device_find); 6348c2a2b8cSThomas Bogendoerfer 635e2a5402eSSrinivas Kandagatla static int devm_nvmem_device_match(struct device *dev, void *res, void *data) 636e2a5402eSSrinivas Kandagatla { 637e2a5402eSSrinivas Kandagatla struct nvmem_device **nvmem = res; 638e2a5402eSSrinivas Kandagatla 639e2a5402eSSrinivas Kandagatla if (WARN_ON(!nvmem || !*nvmem)) 640e2a5402eSSrinivas Kandagatla return 0; 641e2a5402eSSrinivas Kandagatla 642e2a5402eSSrinivas Kandagatla return *nvmem == data; 643e2a5402eSSrinivas Kandagatla } 644e2a5402eSSrinivas Kandagatla 645e2a5402eSSrinivas Kandagatla static void devm_nvmem_device_release(struct device *dev, void *res) 646e2a5402eSSrinivas Kandagatla { 647e2a5402eSSrinivas Kandagatla nvmem_device_put(*(struct nvmem_device **)res); 648e2a5402eSSrinivas Kandagatla } 649e2a5402eSSrinivas Kandagatla 650e2a5402eSSrinivas Kandagatla /** 651e2a5402eSSrinivas Kandagatla * devm_nvmem_device_put() - put alredy got nvmem device 652e2a5402eSSrinivas Kandagatla * 65329143268SVivek Gautam * @dev: Device that uses the nvmem device. 654e2a5402eSSrinivas Kandagatla * @nvmem: pointer to nvmem device allocated by devm_nvmem_cell_get(), 655e2a5402eSSrinivas Kandagatla * that needs to be released. 656e2a5402eSSrinivas Kandagatla */ 657e2a5402eSSrinivas Kandagatla void devm_nvmem_device_put(struct device *dev, struct nvmem_device *nvmem) 658e2a5402eSSrinivas Kandagatla { 659e2a5402eSSrinivas Kandagatla int ret; 660e2a5402eSSrinivas Kandagatla 661e2a5402eSSrinivas Kandagatla ret = devres_release(dev, devm_nvmem_device_release, 662e2a5402eSSrinivas Kandagatla devm_nvmem_device_match, nvmem); 663e2a5402eSSrinivas Kandagatla 664e2a5402eSSrinivas Kandagatla WARN_ON(ret); 665e2a5402eSSrinivas Kandagatla } 666e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_device_put); 667e2a5402eSSrinivas Kandagatla 668e2a5402eSSrinivas Kandagatla /** 669e2a5402eSSrinivas Kandagatla * nvmem_device_put() - put alredy got nvmem device 670e2a5402eSSrinivas Kandagatla * 671e2a5402eSSrinivas Kandagatla * @nvmem: pointer to nvmem device that needs to be released. 672e2a5402eSSrinivas Kandagatla */ 673e2a5402eSSrinivas Kandagatla void nvmem_device_put(struct nvmem_device *nvmem) 674e2a5402eSSrinivas Kandagatla { 675e2a5402eSSrinivas Kandagatla __nvmem_device_put(nvmem); 676e2a5402eSSrinivas Kandagatla } 677e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_put); 678e2a5402eSSrinivas Kandagatla 679e2a5402eSSrinivas Kandagatla /** 680e2a5402eSSrinivas Kandagatla * devm_nvmem_device_get() - Get nvmem cell of device form a given id 681e2a5402eSSrinivas Kandagatla * 68229143268SVivek Gautam * @dev: Device that requests the nvmem device. 68329143268SVivek Gautam * @id: name id for the requested nvmem device. 684e2a5402eSSrinivas Kandagatla * 685e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_cell 686e2a5402eSSrinivas Kandagatla * on success. The nvmem_cell will be freed by the automatically once the 687e2a5402eSSrinivas Kandagatla * device is freed. 688e2a5402eSSrinivas Kandagatla */ 689e2a5402eSSrinivas Kandagatla struct nvmem_device *devm_nvmem_device_get(struct device *dev, const char *id) 690e2a5402eSSrinivas Kandagatla { 691e2a5402eSSrinivas Kandagatla struct nvmem_device **ptr, *nvmem; 692e2a5402eSSrinivas Kandagatla 693e2a5402eSSrinivas Kandagatla ptr = devres_alloc(devm_nvmem_device_release, sizeof(*ptr), GFP_KERNEL); 694e2a5402eSSrinivas Kandagatla if (!ptr) 695e2a5402eSSrinivas Kandagatla return ERR_PTR(-ENOMEM); 696e2a5402eSSrinivas Kandagatla 697e2a5402eSSrinivas Kandagatla nvmem = nvmem_device_get(dev, id); 698e2a5402eSSrinivas Kandagatla if (!IS_ERR(nvmem)) { 699e2a5402eSSrinivas Kandagatla *ptr = nvmem; 700e2a5402eSSrinivas Kandagatla devres_add(dev, ptr); 701e2a5402eSSrinivas Kandagatla } else { 702e2a5402eSSrinivas Kandagatla devres_free(ptr); 703e2a5402eSSrinivas Kandagatla } 704e2a5402eSSrinivas Kandagatla 705e2a5402eSSrinivas Kandagatla return nvmem; 706e2a5402eSSrinivas Kandagatla } 707e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_device_get); 708e2a5402eSSrinivas Kandagatla 709506157beSBartosz Golaszewski static struct nvmem_cell * 710506157beSBartosz Golaszewski nvmem_cell_get_from_lookup(struct device *dev, const char *con_id) 71169aba794SSrinivas Kandagatla { 712506157beSBartosz Golaszewski struct nvmem_cell *cell = ERR_PTR(-ENOENT); 713506157beSBartosz Golaszewski struct nvmem_cell_lookup *lookup; 71469aba794SSrinivas Kandagatla struct nvmem_device *nvmem; 715506157beSBartosz Golaszewski const char *dev_id; 71669aba794SSrinivas Kandagatla 717506157beSBartosz Golaszewski if (!dev) 718506157beSBartosz Golaszewski return ERR_PTR(-EINVAL); 71969aba794SSrinivas Kandagatla 720506157beSBartosz Golaszewski dev_id = dev_name(dev); 721506157beSBartosz Golaszewski 722506157beSBartosz Golaszewski mutex_lock(&nvmem_lookup_mutex); 723506157beSBartosz Golaszewski 724506157beSBartosz Golaszewski list_for_each_entry(lookup, &nvmem_lookup_list, node) { 725506157beSBartosz Golaszewski if ((strcmp(lookup->dev_id, dev_id) == 0) && 726506157beSBartosz Golaszewski (strcmp(lookup->con_id, con_id) == 0)) { 727506157beSBartosz Golaszewski /* This is the right entry. */ 7288c2a2b8cSThomas Bogendoerfer nvmem = __nvmem_device_get((void *)lookup->nvmem_name, 7298c2a2b8cSThomas Bogendoerfer device_match_name); 730cccb3b19SBartosz Golaszewski if (IS_ERR(nvmem)) { 731506157beSBartosz Golaszewski /* Provider may not be registered yet. */ 732cccb3b19SBartosz Golaszewski cell = ERR_CAST(nvmem); 7339bfd8198SAlban Bedel break; 734506157beSBartosz Golaszewski } 735506157beSBartosz Golaszewski 736506157beSBartosz Golaszewski cell = nvmem_find_cell_by_name(nvmem, 737506157beSBartosz Golaszewski lookup->cell_name); 738506157beSBartosz Golaszewski if (!cell) { 739506157beSBartosz Golaszewski __nvmem_device_put(nvmem); 740cccb3b19SBartosz Golaszewski cell = ERR_PTR(-ENOENT); 741506157beSBartosz Golaszewski } 7429bfd8198SAlban Bedel break; 743506157beSBartosz Golaszewski } 744506157beSBartosz Golaszewski } 745506157beSBartosz Golaszewski 746506157beSBartosz Golaszewski mutex_unlock(&nvmem_lookup_mutex); 74769aba794SSrinivas Kandagatla return cell; 74869aba794SSrinivas Kandagatla } 74969aba794SSrinivas Kandagatla 750e701c67cSMasahiro Yamada #if IS_ENABLED(CONFIG_OF) 7513c53e235SArnd Bergmann static struct nvmem_cell * 7520749aa25SSrinivas Kandagatla nvmem_find_cell_by_node(struct nvmem_device *nvmem, struct device_node *np) 7533c53e235SArnd Bergmann { 7541c832674SAlban Bedel struct nvmem_cell *iter, *cell = NULL; 7553c53e235SArnd Bergmann 7563c53e235SArnd Bergmann mutex_lock(&nvmem_mutex); 7571c832674SAlban Bedel list_for_each_entry(iter, &nvmem->cells, node) { 7581c832674SAlban Bedel if (np == iter->np) { 7591c832674SAlban Bedel cell = iter; 7603c53e235SArnd Bergmann break; 7613c53e235SArnd Bergmann } 7621c832674SAlban Bedel } 7633c53e235SArnd Bergmann mutex_unlock(&nvmem_mutex); 7643c53e235SArnd Bergmann 7653c53e235SArnd Bergmann return cell; 7663c53e235SArnd Bergmann } 7673c53e235SArnd Bergmann 76869aba794SSrinivas Kandagatla /** 76969aba794SSrinivas Kandagatla * of_nvmem_cell_get() - Get a nvmem cell from given device node and cell id 77069aba794SSrinivas Kandagatla * 77129143268SVivek Gautam * @np: Device tree node that uses the nvmem cell. 772165589f0SBartosz Golaszewski * @id: nvmem cell name from nvmem-cell-names property, or NULL 773fd0c478cSVivek Gautam * for the cell at index 0 (the lone cell with no accompanying 774fd0c478cSVivek Gautam * nvmem-cell-names property). 77569aba794SSrinivas Kandagatla * 77669aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 77769aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 77869aba794SSrinivas Kandagatla * nvmem_cell_put(). 77969aba794SSrinivas Kandagatla */ 780165589f0SBartosz Golaszewski struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *id) 78169aba794SSrinivas Kandagatla { 78269aba794SSrinivas Kandagatla struct device_node *cell_np, *nvmem_np; 78369aba794SSrinivas Kandagatla struct nvmem_device *nvmem; 784e888d445SBartosz Golaszewski struct nvmem_cell *cell; 785fd0c478cSVivek Gautam int index = 0; 78669aba794SSrinivas Kandagatla 787fd0c478cSVivek Gautam /* if cell name exists, find index to the name */ 788165589f0SBartosz Golaszewski if (id) 789165589f0SBartosz Golaszewski index = of_property_match_string(np, "nvmem-cell-names", id); 79069aba794SSrinivas Kandagatla 79169aba794SSrinivas Kandagatla cell_np = of_parse_phandle(np, "nvmem-cells", index); 79269aba794SSrinivas Kandagatla if (!cell_np) 7935087cc19SAlban Bedel return ERR_PTR(-ENOENT); 79469aba794SSrinivas Kandagatla 79569aba794SSrinivas Kandagatla nvmem_np = of_get_next_parent(cell_np); 79669aba794SSrinivas Kandagatla if (!nvmem_np) 79769aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 79869aba794SSrinivas Kandagatla 7998c2a2b8cSThomas Bogendoerfer nvmem = __nvmem_device_get(nvmem_np, device_match_of_node); 800aad8d097SMasahiro Yamada of_node_put(nvmem_np); 80169aba794SSrinivas Kandagatla if (IS_ERR(nvmem)) 80269aba794SSrinivas Kandagatla return ERR_CAST(nvmem); 80369aba794SSrinivas Kandagatla 8040749aa25SSrinivas Kandagatla cell = nvmem_find_cell_by_node(nvmem, cell_np); 80569aba794SSrinivas Kandagatla if (!cell) { 806e888d445SBartosz Golaszewski __nvmem_device_put(nvmem); 807e888d445SBartosz Golaszewski return ERR_PTR(-ENOENT); 80869aba794SSrinivas Kandagatla } 80969aba794SSrinivas Kandagatla 81069aba794SSrinivas Kandagatla return cell; 81169aba794SSrinivas Kandagatla } 81269aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_nvmem_cell_get); 81369aba794SSrinivas Kandagatla #endif 81469aba794SSrinivas Kandagatla 81569aba794SSrinivas Kandagatla /** 81669aba794SSrinivas Kandagatla * nvmem_cell_get() - Get nvmem cell of device form a given cell name 81769aba794SSrinivas Kandagatla * 81829143268SVivek Gautam * @dev: Device that requests the nvmem cell. 819165589f0SBartosz Golaszewski * @id: nvmem cell name to get (this corresponds with the name from the 820165589f0SBartosz Golaszewski * nvmem-cell-names property for DT systems and with the con_id from 821165589f0SBartosz Golaszewski * the lookup entry for non-DT systems). 82269aba794SSrinivas Kandagatla * 82369aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 82469aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 82569aba794SSrinivas Kandagatla * nvmem_cell_put(). 82669aba794SSrinivas Kandagatla */ 827165589f0SBartosz Golaszewski struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *id) 82869aba794SSrinivas Kandagatla { 82969aba794SSrinivas Kandagatla struct nvmem_cell *cell; 83069aba794SSrinivas Kandagatla 83169aba794SSrinivas Kandagatla if (dev->of_node) { /* try dt first */ 832165589f0SBartosz Golaszewski cell = of_nvmem_cell_get(dev->of_node, id); 83369aba794SSrinivas Kandagatla if (!IS_ERR(cell) || PTR_ERR(cell) == -EPROBE_DEFER) 83469aba794SSrinivas Kandagatla return cell; 83569aba794SSrinivas Kandagatla } 83669aba794SSrinivas Kandagatla 837165589f0SBartosz Golaszewski /* NULL cell id only allowed for device tree; invalid otherwise */ 838165589f0SBartosz Golaszewski if (!id) 83987ed1405SDouglas Anderson return ERR_PTR(-EINVAL); 84087ed1405SDouglas Anderson 841165589f0SBartosz Golaszewski return nvmem_cell_get_from_lookup(dev, id); 84269aba794SSrinivas Kandagatla } 84369aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_get); 84469aba794SSrinivas Kandagatla 84569aba794SSrinivas Kandagatla static void devm_nvmem_cell_release(struct device *dev, void *res) 84669aba794SSrinivas Kandagatla { 84769aba794SSrinivas Kandagatla nvmem_cell_put(*(struct nvmem_cell **)res); 84869aba794SSrinivas Kandagatla } 84969aba794SSrinivas Kandagatla 85069aba794SSrinivas Kandagatla /** 85169aba794SSrinivas Kandagatla * devm_nvmem_cell_get() - Get nvmem cell of device form a given id 85269aba794SSrinivas Kandagatla * 85329143268SVivek Gautam * @dev: Device that requests the nvmem cell. 85429143268SVivek Gautam * @id: nvmem cell name id to get. 85569aba794SSrinivas Kandagatla * 85669aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 85769aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 85869aba794SSrinivas Kandagatla * automatically once the device is freed. 85969aba794SSrinivas Kandagatla */ 86069aba794SSrinivas Kandagatla struct nvmem_cell *devm_nvmem_cell_get(struct device *dev, const char *id) 86169aba794SSrinivas Kandagatla { 86269aba794SSrinivas Kandagatla struct nvmem_cell **ptr, *cell; 86369aba794SSrinivas Kandagatla 86469aba794SSrinivas Kandagatla ptr = devres_alloc(devm_nvmem_cell_release, sizeof(*ptr), GFP_KERNEL); 86569aba794SSrinivas Kandagatla if (!ptr) 86669aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 86769aba794SSrinivas Kandagatla 86869aba794SSrinivas Kandagatla cell = nvmem_cell_get(dev, id); 86969aba794SSrinivas Kandagatla if (!IS_ERR(cell)) { 87069aba794SSrinivas Kandagatla *ptr = cell; 87169aba794SSrinivas Kandagatla devres_add(dev, ptr); 87269aba794SSrinivas Kandagatla } else { 87369aba794SSrinivas Kandagatla devres_free(ptr); 87469aba794SSrinivas Kandagatla } 87569aba794SSrinivas Kandagatla 87669aba794SSrinivas Kandagatla return cell; 87769aba794SSrinivas Kandagatla } 87869aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_cell_get); 87969aba794SSrinivas Kandagatla 88069aba794SSrinivas Kandagatla static int devm_nvmem_cell_match(struct device *dev, void *res, void *data) 88169aba794SSrinivas Kandagatla { 88269aba794SSrinivas Kandagatla struct nvmem_cell **c = res; 88369aba794SSrinivas Kandagatla 88469aba794SSrinivas Kandagatla if (WARN_ON(!c || !*c)) 88569aba794SSrinivas Kandagatla return 0; 88669aba794SSrinivas Kandagatla 88769aba794SSrinivas Kandagatla return *c == data; 88869aba794SSrinivas Kandagatla } 88969aba794SSrinivas Kandagatla 89069aba794SSrinivas Kandagatla /** 89169aba794SSrinivas Kandagatla * devm_nvmem_cell_put() - Release previously allocated nvmem cell 89269aba794SSrinivas Kandagatla * from devm_nvmem_cell_get. 89369aba794SSrinivas Kandagatla * 89429143268SVivek Gautam * @dev: Device that requests the nvmem cell. 89529143268SVivek Gautam * @cell: Previously allocated nvmem cell by devm_nvmem_cell_get(). 89669aba794SSrinivas Kandagatla */ 89769aba794SSrinivas Kandagatla void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell) 89869aba794SSrinivas Kandagatla { 89969aba794SSrinivas Kandagatla int ret; 90069aba794SSrinivas Kandagatla 90169aba794SSrinivas Kandagatla ret = devres_release(dev, devm_nvmem_cell_release, 90269aba794SSrinivas Kandagatla devm_nvmem_cell_match, cell); 90369aba794SSrinivas Kandagatla 90469aba794SSrinivas Kandagatla WARN_ON(ret); 90569aba794SSrinivas Kandagatla } 90669aba794SSrinivas Kandagatla EXPORT_SYMBOL(devm_nvmem_cell_put); 90769aba794SSrinivas Kandagatla 90869aba794SSrinivas Kandagatla /** 90969aba794SSrinivas Kandagatla * nvmem_cell_put() - Release previously allocated nvmem cell. 91069aba794SSrinivas Kandagatla * 91129143268SVivek Gautam * @cell: Previously allocated nvmem cell by nvmem_cell_get(). 91269aba794SSrinivas Kandagatla */ 91369aba794SSrinivas Kandagatla void nvmem_cell_put(struct nvmem_cell *cell) 91469aba794SSrinivas Kandagatla { 91569aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 91669aba794SSrinivas Kandagatla 91769aba794SSrinivas Kandagatla __nvmem_device_put(nvmem); 91869aba794SSrinivas Kandagatla } 91969aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_put); 92069aba794SSrinivas Kandagatla 921f7c04f16SMasahiro Yamada static void nvmem_shift_read_buffer_in_place(struct nvmem_cell *cell, void *buf) 92269aba794SSrinivas Kandagatla { 92369aba794SSrinivas Kandagatla u8 *p, *b; 9242fe518feSJorge Ramirez-Ortiz int i, extra, bit_offset = cell->bit_offset; 92569aba794SSrinivas Kandagatla 92669aba794SSrinivas Kandagatla p = b = buf; 92769aba794SSrinivas Kandagatla if (bit_offset) { 92869aba794SSrinivas Kandagatla /* First shift */ 92969aba794SSrinivas Kandagatla *b++ >>= bit_offset; 93069aba794SSrinivas Kandagatla 93169aba794SSrinivas Kandagatla /* setup rest of the bytes if any */ 93269aba794SSrinivas Kandagatla for (i = 1; i < cell->bytes; i++) { 93369aba794SSrinivas Kandagatla /* Get bits from next byte and shift them towards msb */ 93469aba794SSrinivas Kandagatla *p |= *b << (BITS_PER_BYTE - bit_offset); 93569aba794SSrinivas Kandagatla 93669aba794SSrinivas Kandagatla p = b; 93769aba794SSrinivas Kandagatla *b++ >>= bit_offset; 93869aba794SSrinivas Kandagatla } 9392fe518feSJorge Ramirez-Ortiz } else { 9402fe518feSJorge Ramirez-Ortiz /* point to the msb */ 9412fe518feSJorge Ramirez-Ortiz p += cell->bytes - 1; 9422fe518feSJorge Ramirez-Ortiz } 94369aba794SSrinivas Kandagatla 94469aba794SSrinivas Kandagatla /* result fits in less bytes */ 9452fe518feSJorge Ramirez-Ortiz extra = cell->bytes - DIV_ROUND_UP(cell->nbits, BITS_PER_BYTE); 9462fe518feSJorge Ramirez-Ortiz while (--extra >= 0) 94769aba794SSrinivas Kandagatla *p-- = 0; 9482fe518feSJorge Ramirez-Ortiz 94969aba794SSrinivas Kandagatla /* clear msb bits if any leftover in the last byte */ 95069aba794SSrinivas Kandagatla *p &= GENMASK((cell->nbits%BITS_PER_BYTE) - 1, 0); 95169aba794SSrinivas Kandagatla } 95269aba794SSrinivas Kandagatla 95369aba794SSrinivas Kandagatla static int __nvmem_cell_read(struct nvmem_device *nvmem, 95469aba794SSrinivas Kandagatla struct nvmem_cell *cell, 95569aba794SSrinivas Kandagatla void *buf, size_t *len) 95669aba794SSrinivas Kandagatla { 95769aba794SSrinivas Kandagatla int rc; 95869aba794SSrinivas Kandagatla 959795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, cell->offset, buf, cell->bytes); 96069aba794SSrinivas Kandagatla 961287980e4SArnd Bergmann if (rc) 96269aba794SSrinivas Kandagatla return rc; 96369aba794SSrinivas Kandagatla 96469aba794SSrinivas Kandagatla /* shift bits in-place */ 965cbf854abSAxel Lin if (cell->bit_offset || cell->nbits) 96669aba794SSrinivas Kandagatla nvmem_shift_read_buffer_in_place(cell, buf); 96769aba794SSrinivas Kandagatla 9683b4a6877SVivek Gautam if (len) 96969aba794SSrinivas Kandagatla *len = cell->bytes; 97069aba794SSrinivas Kandagatla 97169aba794SSrinivas Kandagatla return 0; 97269aba794SSrinivas Kandagatla } 97369aba794SSrinivas Kandagatla 97469aba794SSrinivas Kandagatla /** 97569aba794SSrinivas Kandagatla * nvmem_cell_read() - Read a given nvmem cell 97669aba794SSrinivas Kandagatla * 97769aba794SSrinivas Kandagatla * @cell: nvmem cell to be read. 9783b4a6877SVivek Gautam * @len: pointer to length of cell which will be populated on successful read; 9793b4a6877SVivek Gautam * can be NULL. 98069aba794SSrinivas Kandagatla * 981b577fafcSBrian Norris * Return: ERR_PTR() on error or a valid pointer to a buffer on success. The 982b577fafcSBrian Norris * buffer should be freed by the consumer with a kfree(). 98369aba794SSrinivas Kandagatla */ 98469aba794SSrinivas Kandagatla void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len) 98569aba794SSrinivas Kandagatla { 98669aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 98769aba794SSrinivas Kandagatla u8 *buf; 98869aba794SSrinivas Kandagatla int rc; 98969aba794SSrinivas Kandagatla 990795ddd18SSrinivas Kandagatla if (!nvmem) 99169aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 99269aba794SSrinivas Kandagatla 99369aba794SSrinivas Kandagatla buf = kzalloc(cell->bytes, GFP_KERNEL); 99469aba794SSrinivas Kandagatla if (!buf) 99569aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 99669aba794SSrinivas Kandagatla 99769aba794SSrinivas Kandagatla rc = __nvmem_cell_read(nvmem, cell, buf, len); 998287980e4SArnd Bergmann if (rc) { 99969aba794SSrinivas Kandagatla kfree(buf); 100069aba794SSrinivas Kandagatla return ERR_PTR(rc); 100169aba794SSrinivas Kandagatla } 100269aba794SSrinivas Kandagatla 100369aba794SSrinivas Kandagatla return buf; 100469aba794SSrinivas Kandagatla } 100569aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_read); 100669aba794SSrinivas Kandagatla 1007f7c04f16SMasahiro Yamada static void *nvmem_cell_prepare_write_buffer(struct nvmem_cell *cell, 100869aba794SSrinivas Kandagatla u8 *_buf, int len) 100969aba794SSrinivas Kandagatla { 101069aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 101169aba794SSrinivas Kandagatla int i, rc, nbits, bit_offset = cell->bit_offset; 101269aba794SSrinivas Kandagatla u8 v, *p, *buf, *b, pbyte, pbits; 101369aba794SSrinivas Kandagatla 101469aba794SSrinivas Kandagatla nbits = cell->nbits; 101569aba794SSrinivas Kandagatla buf = kzalloc(cell->bytes, GFP_KERNEL); 101669aba794SSrinivas Kandagatla if (!buf) 101769aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 101869aba794SSrinivas Kandagatla 101969aba794SSrinivas Kandagatla memcpy(buf, _buf, len); 102069aba794SSrinivas Kandagatla p = b = buf; 102169aba794SSrinivas Kandagatla 102269aba794SSrinivas Kandagatla if (bit_offset) { 102369aba794SSrinivas Kandagatla pbyte = *b; 102469aba794SSrinivas Kandagatla *b <<= bit_offset; 102569aba794SSrinivas Kandagatla 102669aba794SSrinivas Kandagatla /* setup the first byte with lsb bits from nvmem */ 1027795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, cell->offset, &v, 1); 102850808bfcSMathieu Malaterre if (rc) 102950808bfcSMathieu Malaterre goto err; 103069aba794SSrinivas Kandagatla *b++ |= GENMASK(bit_offset - 1, 0) & v; 103169aba794SSrinivas Kandagatla 103269aba794SSrinivas Kandagatla /* setup rest of the byte if any */ 103369aba794SSrinivas Kandagatla for (i = 1; i < cell->bytes; i++) { 103469aba794SSrinivas Kandagatla /* Get last byte bits and shift them towards lsb */ 103569aba794SSrinivas Kandagatla pbits = pbyte >> (BITS_PER_BYTE - 1 - bit_offset); 103669aba794SSrinivas Kandagatla pbyte = *b; 103769aba794SSrinivas Kandagatla p = b; 103869aba794SSrinivas Kandagatla *b <<= bit_offset; 103969aba794SSrinivas Kandagatla *b++ |= pbits; 104069aba794SSrinivas Kandagatla } 104169aba794SSrinivas Kandagatla } 104269aba794SSrinivas Kandagatla 104369aba794SSrinivas Kandagatla /* if it's not end on byte boundary */ 104469aba794SSrinivas Kandagatla if ((nbits + bit_offset) % BITS_PER_BYTE) { 104569aba794SSrinivas Kandagatla /* setup the last byte with msb bits from nvmem */ 1046795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, 104769aba794SSrinivas Kandagatla cell->offset + cell->bytes - 1, &v, 1); 104850808bfcSMathieu Malaterre if (rc) 104950808bfcSMathieu Malaterre goto err; 105069aba794SSrinivas Kandagatla *p |= GENMASK(7, (nbits + bit_offset) % BITS_PER_BYTE) & v; 105169aba794SSrinivas Kandagatla 105269aba794SSrinivas Kandagatla } 105369aba794SSrinivas Kandagatla 105469aba794SSrinivas Kandagatla return buf; 105550808bfcSMathieu Malaterre err: 105650808bfcSMathieu Malaterre kfree(buf); 105750808bfcSMathieu Malaterre return ERR_PTR(rc); 105869aba794SSrinivas Kandagatla } 105969aba794SSrinivas Kandagatla 106069aba794SSrinivas Kandagatla /** 106169aba794SSrinivas Kandagatla * nvmem_cell_write() - Write to a given nvmem cell 106269aba794SSrinivas Kandagatla * 106369aba794SSrinivas Kandagatla * @cell: nvmem cell to be written. 106469aba794SSrinivas Kandagatla * @buf: Buffer to be written. 106569aba794SSrinivas Kandagatla * @len: length of buffer to be written to nvmem cell. 106669aba794SSrinivas Kandagatla * 106769aba794SSrinivas Kandagatla * Return: length of bytes written or negative on failure. 106869aba794SSrinivas Kandagatla */ 106969aba794SSrinivas Kandagatla int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len) 107069aba794SSrinivas Kandagatla { 107169aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 107269aba794SSrinivas Kandagatla int rc; 107369aba794SSrinivas Kandagatla 1074795ddd18SSrinivas Kandagatla if (!nvmem || nvmem->read_only || 107569aba794SSrinivas Kandagatla (cell->bit_offset == 0 && len != cell->bytes)) 107669aba794SSrinivas Kandagatla return -EINVAL; 107769aba794SSrinivas Kandagatla 107869aba794SSrinivas Kandagatla if (cell->bit_offset || cell->nbits) { 107969aba794SSrinivas Kandagatla buf = nvmem_cell_prepare_write_buffer(cell, buf, len); 108069aba794SSrinivas Kandagatla if (IS_ERR(buf)) 108169aba794SSrinivas Kandagatla return PTR_ERR(buf); 108269aba794SSrinivas Kandagatla } 108369aba794SSrinivas Kandagatla 1084795ddd18SSrinivas Kandagatla rc = nvmem_reg_write(nvmem, cell->offset, buf, cell->bytes); 108569aba794SSrinivas Kandagatla 108669aba794SSrinivas Kandagatla /* free the tmp buffer */ 1087ace22170SAxel Lin if (cell->bit_offset || cell->nbits) 108869aba794SSrinivas Kandagatla kfree(buf); 108969aba794SSrinivas Kandagatla 1090287980e4SArnd Bergmann if (rc) 109169aba794SSrinivas Kandagatla return rc; 109269aba794SSrinivas Kandagatla 109369aba794SSrinivas Kandagatla return len; 109469aba794SSrinivas Kandagatla } 109569aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_write); 109669aba794SSrinivas Kandagatla 10976bb317ceSYangtao Li static int nvmem_cell_read_common(struct device *dev, const char *cell_id, 10986bb317ceSYangtao Li void *val, size_t count) 10990a9b2d1cSFabrice Gasnier { 11000a9b2d1cSFabrice Gasnier struct nvmem_cell *cell; 11010a9b2d1cSFabrice Gasnier void *buf; 11020a9b2d1cSFabrice Gasnier size_t len; 11030a9b2d1cSFabrice Gasnier 11040a9b2d1cSFabrice Gasnier cell = nvmem_cell_get(dev, cell_id); 11050a9b2d1cSFabrice Gasnier if (IS_ERR(cell)) 11060a9b2d1cSFabrice Gasnier return PTR_ERR(cell); 11070a9b2d1cSFabrice Gasnier 11080a9b2d1cSFabrice Gasnier buf = nvmem_cell_read(cell, &len); 11090a9b2d1cSFabrice Gasnier if (IS_ERR(buf)) { 11100a9b2d1cSFabrice Gasnier nvmem_cell_put(cell); 11110a9b2d1cSFabrice Gasnier return PTR_ERR(buf); 11120a9b2d1cSFabrice Gasnier } 11136bb317ceSYangtao Li if (len != count) { 11140a9b2d1cSFabrice Gasnier kfree(buf); 11150a9b2d1cSFabrice Gasnier nvmem_cell_put(cell); 11160a9b2d1cSFabrice Gasnier return -EINVAL; 11170a9b2d1cSFabrice Gasnier } 11186bb317ceSYangtao Li memcpy(val, buf, count); 11190a9b2d1cSFabrice Gasnier kfree(buf); 11200a9b2d1cSFabrice Gasnier nvmem_cell_put(cell); 11210a9b2d1cSFabrice Gasnier 11220a9b2d1cSFabrice Gasnier return 0; 11230a9b2d1cSFabrice Gasnier } 11246bb317ceSYangtao Li 11256bb317ceSYangtao Li /** 11266bb317ceSYangtao Li * nvmem_cell_read_u16() - Read a cell value as an u16 11276bb317ceSYangtao Li * 11286bb317ceSYangtao Li * @dev: Device that requests the nvmem cell. 11296bb317ceSYangtao Li * @cell_id: Name of nvmem cell to read. 11306bb317ceSYangtao Li * @val: pointer to output value. 11316bb317ceSYangtao Li * 11326bb317ceSYangtao Li * Return: 0 on success or negative errno. 11336bb317ceSYangtao Li */ 11346bb317ceSYangtao Li int nvmem_cell_read_u16(struct device *dev, const char *cell_id, u16 *val) 11356bb317ceSYangtao Li { 11366bb317ceSYangtao Li return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val)); 11376bb317ceSYangtao Li } 11380a9b2d1cSFabrice Gasnier EXPORT_SYMBOL_GPL(nvmem_cell_read_u16); 11390a9b2d1cSFabrice Gasnier 11400a9b2d1cSFabrice Gasnier /** 1141d026d70aSLeonard Crestez * nvmem_cell_read_u32() - Read a cell value as an u32 1142d026d70aSLeonard Crestez * 1143d026d70aSLeonard Crestez * @dev: Device that requests the nvmem cell. 1144d026d70aSLeonard Crestez * @cell_id: Name of nvmem cell to read. 1145d026d70aSLeonard Crestez * @val: pointer to output value. 1146d026d70aSLeonard Crestez * 1147d026d70aSLeonard Crestez * Return: 0 on success or negative errno. 1148d026d70aSLeonard Crestez */ 1149d026d70aSLeonard Crestez int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val) 1150d026d70aSLeonard Crestez { 11516bb317ceSYangtao Li return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val)); 1152d026d70aSLeonard Crestez } 1153d026d70aSLeonard Crestez EXPORT_SYMBOL_GPL(nvmem_cell_read_u32); 1154d026d70aSLeonard Crestez 1155d026d70aSLeonard Crestez /** 11568b977c54SYangtao Li * nvmem_cell_read_u64() - Read a cell value as an u64 11578b977c54SYangtao Li * 11588b977c54SYangtao Li * @dev: Device that requests the nvmem cell. 11598b977c54SYangtao Li * @cell_id: Name of nvmem cell to read. 11608b977c54SYangtao Li * @val: pointer to output value. 11618b977c54SYangtao Li * 11628b977c54SYangtao Li * Return: 0 on success or negative errno. 11638b977c54SYangtao Li */ 11648b977c54SYangtao Li int nvmem_cell_read_u64(struct device *dev, const char *cell_id, u64 *val) 11658b977c54SYangtao Li { 11668b977c54SYangtao Li return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val)); 11678b977c54SYangtao Li } 11688b977c54SYangtao Li EXPORT_SYMBOL_GPL(nvmem_cell_read_u64); 11698b977c54SYangtao Li 11708b977c54SYangtao Li /** 1171e2a5402eSSrinivas Kandagatla * nvmem_device_cell_read() - Read a given nvmem device and cell 1172e2a5402eSSrinivas Kandagatla * 1173e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to read from. 1174e2a5402eSSrinivas Kandagatla * @info: nvmem cell info to be read. 1175e2a5402eSSrinivas Kandagatla * @buf: buffer pointer which will be populated on successful read. 1176e2a5402eSSrinivas Kandagatla * 1177e2a5402eSSrinivas Kandagatla * Return: length of successful bytes read on success and negative 1178e2a5402eSSrinivas Kandagatla * error code on error. 1179e2a5402eSSrinivas Kandagatla */ 1180e2a5402eSSrinivas Kandagatla ssize_t nvmem_device_cell_read(struct nvmem_device *nvmem, 1181e2a5402eSSrinivas Kandagatla struct nvmem_cell_info *info, void *buf) 1182e2a5402eSSrinivas Kandagatla { 1183e2a5402eSSrinivas Kandagatla struct nvmem_cell cell; 1184e2a5402eSSrinivas Kandagatla int rc; 1185e2a5402eSSrinivas Kandagatla ssize_t len; 1186e2a5402eSSrinivas Kandagatla 1187795ddd18SSrinivas Kandagatla if (!nvmem) 1188e2a5402eSSrinivas Kandagatla return -EINVAL; 1189e2a5402eSSrinivas Kandagatla 1190e2a5402eSSrinivas Kandagatla rc = nvmem_cell_info_to_nvmem_cell(nvmem, info, &cell); 1191287980e4SArnd Bergmann if (rc) 1192e2a5402eSSrinivas Kandagatla return rc; 1193e2a5402eSSrinivas Kandagatla 1194e2a5402eSSrinivas Kandagatla rc = __nvmem_cell_read(nvmem, &cell, buf, &len); 1195287980e4SArnd Bergmann if (rc) 1196e2a5402eSSrinivas Kandagatla return rc; 1197e2a5402eSSrinivas Kandagatla 1198e2a5402eSSrinivas Kandagatla return len; 1199e2a5402eSSrinivas Kandagatla } 1200e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_cell_read); 1201e2a5402eSSrinivas Kandagatla 1202e2a5402eSSrinivas Kandagatla /** 1203e2a5402eSSrinivas Kandagatla * nvmem_device_cell_write() - Write cell to a given nvmem device 1204e2a5402eSSrinivas Kandagatla * 1205e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to be written to. 120629143268SVivek Gautam * @info: nvmem cell info to be written. 1207e2a5402eSSrinivas Kandagatla * @buf: buffer to be written to cell. 1208e2a5402eSSrinivas Kandagatla * 1209e2a5402eSSrinivas Kandagatla * Return: length of bytes written or negative error code on failure. 121048f63a2cSBartosz Golaszewski */ 1211e2a5402eSSrinivas Kandagatla int nvmem_device_cell_write(struct nvmem_device *nvmem, 1212e2a5402eSSrinivas Kandagatla struct nvmem_cell_info *info, void *buf) 1213e2a5402eSSrinivas Kandagatla { 1214e2a5402eSSrinivas Kandagatla struct nvmem_cell cell; 1215e2a5402eSSrinivas Kandagatla int rc; 1216e2a5402eSSrinivas Kandagatla 1217795ddd18SSrinivas Kandagatla if (!nvmem) 1218e2a5402eSSrinivas Kandagatla return -EINVAL; 1219e2a5402eSSrinivas Kandagatla 1220e2a5402eSSrinivas Kandagatla rc = nvmem_cell_info_to_nvmem_cell(nvmem, info, &cell); 1221287980e4SArnd Bergmann if (rc) 1222e2a5402eSSrinivas Kandagatla return rc; 1223e2a5402eSSrinivas Kandagatla 1224e2a5402eSSrinivas Kandagatla return nvmem_cell_write(&cell, buf, cell.bytes); 1225e2a5402eSSrinivas Kandagatla } 1226e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_cell_write); 1227e2a5402eSSrinivas Kandagatla 1228e2a5402eSSrinivas Kandagatla /** 1229e2a5402eSSrinivas Kandagatla * nvmem_device_read() - Read from a given nvmem device 1230e2a5402eSSrinivas Kandagatla * 1231e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to read from. 1232e2a5402eSSrinivas Kandagatla * @offset: offset in nvmem device. 1233e2a5402eSSrinivas Kandagatla * @bytes: number of bytes to read. 1234e2a5402eSSrinivas Kandagatla * @buf: buffer pointer which will be populated on successful read. 1235e2a5402eSSrinivas Kandagatla * 1236e2a5402eSSrinivas Kandagatla * Return: length of successful bytes read on success and negative 1237e2a5402eSSrinivas Kandagatla * error code on error. 1238e2a5402eSSrinivas Kandagatla */ 1239e2a5402eSSrinivas Kandagatla int nvmem_device_read(struct nvmem_device *nvmem, 1240e2a5402eSSrinivas Kandagatla unsigned int offset, 1241e2a5402eSSrinivas Kandagatla size_t bytes, void *buf) 1242e2a5402eSSrinivas Kandagatla { 1243e2a5402eSSrinivas Kandagatla int rc; 1244e2a5402eSSrinivas Kandagatla 1245795ddd18SSrinivas Kandagatla if (!nvmem) 1246e2a5402eSSrinivas Kandagatla return -EINVAL; 1247e2a5402eSSrinivas Kandagatla 1248795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, offset, buf, bytes); 1249e2a5402eSSrinivas Kandagatla 1250287980e4SArnd Bergmann if (rc) 1251e2a5402eSSrinivas Kandagatla return rc; 1252e2a5402eSSrinivas Kandagatla 1253e2a5402eSSrinivas Kandagatla return bytes; 1254e2a5402eSSrinivas Kandagatla } 1255e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_read); 1256e2a5402eSSrinivas Kandagatla 1257e2a5402eSSrinivas Kandagatla /** 1258e2a5402eSSrinivas Kandagatla * nvmem_device_write() - Write cell to a given nvmem device 1259e2a5402eSSrinivas Kandagatla * 1260e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to be written to. 1261e2a5402eSSrinivas Kandagatla * @offset: offset in nvmem device. 1262e2a5402eSSrinivas Kandagatla * @bytes: number of bytes to write. 1263e2a5402eSSrinivas Kandagatla * @buf: buffer to be written. 1264e2a5402eSSrinivas Kandagatla * 1265e2a5402eSSrinivas Kandagatla * Return: length of bytes written or negative error code on failure. 126648f63a2cSBartosz Golaszewski */ 1267e2a5402eSSrinivas Kandagatla int nvmem_device_write(struct nvmem_device *nvmem, 1268e2a5402eSSrinivas Kandagatla unsigned int offset, 1269e2a5402eSSrinivas Kandagatla size_t bytes, void *buf) 1270e2a5402eSSrinivas Kandagatla { 1271e2a5402eSSrinivas Kandagatla int rc; 1272e2a5402eSSrinivas Kandagatla 1273795ddd18SSrinivas Kandagatla if (!nvmem) 1274e2a5402eSSrinivas Kandagatla return -EINVAL; 1275e2a5402eSSrinivas Kandagatla 1276795ddd18SSrinivas Kandagatla rc = nvmem_reg_write(nvmem, offset, buf, bytes); 1277e2a5402eSSrinivas Kandagatla 1278287980e4SArnd Bergmann if (rc) 1279e2a5402eSSrinivas Kandagatla return rc; 1280e2a5402eSSrinivas Kandagatla 1281e2a5402eSSrinivas Kandagatla 1282e2a5402eSSrinivas Kandagatla return bytes; 1283e2a5402eSSrinivas Kandagatla } 1284e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_write); 1285e2a5402eSSrinivas Kandagatla 1286d7b9fd16SBartosz Golaszewski /** 1287b985f4cbSBartosz Golaszewski * nvmem_add_cell_table() - register a table of cell info entries 1288b985f4cbSBartosz Golaszewski * 1289b985f4cbSBartosz Golaszewski * @table: table of cell info entries 1290b985f4cbSBartosz Golaszewski */ 1291b985f4cbSBartosz Golaszewski void nvmem_add_cell_table(struct nvmem_cell_table *table) 1292b985f4cbSBartosz Golaszewski { 1293b985f4cbSBartosz Golaszewski mutex_lock(&nvmem_cell_mutex); 1294b985f4cbSBartosz Golaszewski list_add_tail(&table->node, &nvmem_cell_tables); 1295b985f4cbSBartosz Golaszewski mutex_unlock(&nvmem_cell_mutex); 1296b985f4cbSBartosz Golaszewski } 1297b985f4cbSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_add_cell_table); 1298b985f4cbSBartosz Golaszewski 1299b985f4cbSBartosz Golaszewski /** 1300b985f4cbSBartosz Golaszewski * nvmem_del_cell_table() - remove a previously registered cell info table 1301b985f4cbSBartosz Golaszewski * 1302b985f4cbSBartosz Golaszewski * @table: table of cell info entries 1303b985f4cbSBartosz Golaszewski */ 1304b985f4cbSBartosz Golaszewski void nvmem_del_cell_table(struct nvmem_cell_table *table) 1305b985f4cbSBartosz Golaszewski { 1306b985f4cbSBartosz Golaszewski mutex_lock(&nvmem_cell_mutex); 1307b985f4cbSBartosz Golaszewski list_del(&table->node); 1308b985f4cbSBartosz Golaszewski mutex_unlock(&nvmem_cell_mutex); 1309b985f4cbSBartosz Golaszewski } 1310b985f4cbSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_del_cell_table); 1311b985f4cbSBartosz Golaszewski 1312b985f4cbSBartosz Golaszewski /** 1313506157beSBartosz Golaszewski * nvmem_add_cell_lookups() - register a list of cell lookup entries 1314506157beSBartosz Golaszewski * 1315506157beSBartosz Golaszewski * @entries: array of cell lookup entries 1316506157beSBartosz Golaszewski * @nentries: number of cell lookup entries in the array 1317506157beSBartosz Golaszewski */ 1318506157beSBartosz Golaszewski void nvmem_add_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries) 1319506157beSBartosz Golaszewski { 1320506157beSBartosz Golaszewski int i; 1321506157beSBartosz Golaszewski 1322506157beSBartosz Golaszewski mutex_lock(&nvmem_lookup_mutex); 1323506157beSBartosz Golaszewski for (i = 0; i < nentries; i++) 1324506157beSBartosz Golaszewski list_add_tail(&entries[i].node, &nvmem_lookup_list); 1325506157beSBartosz Golaszewski mutex_unlock(&nvmem_lookup_mutex); 1326506157beSBartosz Golaszewski } 1327506157beSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_add_cell_lookups); 1328506157beSBartosz Golaszewski 1329506157beSBartosz Golaszewski /** 1330506157beSBartosz Golaszewski * nvmem_del_cell_lookups() - remove a list of previously added cell lookup 1331506157beSBartosz Golaszewski * entries 1332506157beSBartosz Golaszewski * 1333506157beSBartosz Golaszewski * @entries: array of cell lookup entries 1334506157beSBartosz Golaszewski * @nentries: number of cell lookup entries in the array 1335506157beSBartosz Golaszewski */ 1336506157beSBartosz Golaszewski void nvmem_del_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries) 1337506157beSBartosz Golaszewski { 1338506157beSBartosz Golaszewski int i; 1339506157beSBartosz Golaszewski 1340506157beSBartosz Golaszewski mutex_lock(&nvmem_lookup_mutex); 1341506157beSBartosz Golaszewski for (i = 0; i < nentries; i++) 1342506157beSBartosz Golaszewski list_del(&entries[i].node); 1343506157beSBartosz Golaszewski mutex_unlock(&nvmem_lookup_mutex); 1344506157beSBartosz Golaszewski } 1345506157beSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_del_cell_lookups); 1346506157beSBartosz Golaszewski 1347506157beSBartosz Golaszewski /** 1348d7b9fd16SBartosz Golaszewski * nvmem_dev_name() - Get the name of a given nvmem device. 1349d7b9fd16SBartosz Golaszewski * 1350d7b9fd16SBartosz Golaszewski * @nvmem: nvmem device. 1351d7b9fd16SBartosz Golaszewski * 1352d7b9fd16SBartosz Golaszewski * Return: name of the nvmem device. 1353d7b9fd16SBartosz Golaszewski */ 1354d7b9fd16SBartosz Golaszewski const char *nvmem_dev_name(struct nvmem_device *nvmem) 1355d7b9fd16SBartosz Golaszewski { 1356d7b9fd16SBartosz Golaszewski return dev_name(&nvmem->dev); 1357d7b9fd16SBartosz Golaszewski } 1358d7b9fd16SBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_dev_name); 1359d7b9fd16SBartosz Golaszewski 1360eace75cfSSrinivas Kandagatla static int __init nvmem_init(void) 1361eace75cfSSrinivas Kandagatla { 1362eace75cfSSrinivas Kandagatla return bus_register(&nvmem_bus_type); 1363eace75cfSSrinivas Kandagatla } 1364eace75cfSSrinivas Kandagatla 1365eace75cfSSrinivas Kandagatla static void __exit nvmem_exit(void) 1366eace75cfSSrinivas Kandagatla { 1367eace75cfSSrinivas Kandagatla bus_unregister(&nvmem_bus_type); 1368eace75cfSSrinivas Kandagatla } 1369eace75cfSSrinivas Kandagatla 1370eace75cfSSrinivas Kandagatla subsys_initcall(nvmem_init); 1371eace75cfSSrinivas Kandagatla module_exit(nvmem_exit); 1372eace75cfSSrinivas Kandagatla 1373eace75cfSSrinivas Kandagatla MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org"); 1374eace75cfSSrinivas Kandagatla MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com"); 1375eace75cfSSrinivas Kandagatla MODULE_DESCRIPTION("nvmem Driver Core"); 1376eace75cfSSrinivas Kandagatla MODULE_LICENSE("GPL v2"); 1377