1b1c1db98SBartosz Golaszewski // SPDX-License-Identifier: GPL-2.0 2eace75cfSSrinivas Kandagatla /* 3eace75cfSSrinivas Kandagatla * nvmem framework core. 4eace75cfSSrinivas Kandagatla * 5eace75cfSSrinivas Kandagatla * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org> 6eace75cfSSrinivas Kandagatla * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com> 7eace75cfSSrinivas Kandagatla */ 8eace75cfSSrinivas Kandagatla 9eace75cfSSrinivas Kandagatla #include <linux/device.h> 10eace75cfSSrinivas Kandagatla #include <linux/export.h> 11eace75cfSSrinivas Kandagatla #include <linux/fs.h> 12eace75cfSSrinivas Kandagatla #include <linux/idr.h> 13eace75cfSSrinivas Kandagatla #include <linux/init.h> 14c1de7f43SBartosz Golaszewski #include <linux/kref.h> 15eace75cfSSrinivas Kandagatla #include <linux/module.h> 16eace75cfSSrinivas Kandagatla #include <linux/nvmem-consumer.h> 17eace75cfSSrinivas Kandagatla #include <linux/nvmem-provider.h> 18eace75cfSSrinivas Kandagatla #include <linux/of.h> 19eace75cfSSrinivas Kandagatla #include <linux/slab.h> 20eace75cfSSrinivas Kandagatla 21eace75cfSSrinivas Kandagatla struct nvmem_device { 22eace75cfSSrinivas Kandagatla struct module *owner; 23eace75cfSSrinivas Kandagatla struct device dev; 24eace75cfSSrinivas Kandagatla int stride; 25eace75cfSSrinivas Kandagatla int word_size; 26eace75cfSSrinivas Kandagatla int id; 27c1de7f43SBartosz Golaszewski struct kref refcnt; 28eace75cfSSrinivas Kandagatla size_t size; 29eace75cfSSrinivas Kandagatla bool read_only; 30b6c217abSAndrew Lunn int flags; 31b6c217abSAndrew Lunn struct bin_attribute eeprom; 32b6c217abSAndrew Lunn struct device *base_dev; 33c7235ee3SBartosz Golaszewski struct list_head cells; 34795ddd18SSrinivas Kandagatla nvmem_reg_read_t reg_read; 35795ddd18SSrinivas Kandagatla nvmem_reg_write_t reg_write; 36795ddd18SSrinivas Kandagatla void *priv; 37eace75cfSSrinivas Kandagatla }; 38eace75cfSSrinivas Kandagatla 39b6c217abSAndrew Lunn #define FLAG_COMPAT BIT(0) 40b6c217abSAndrew Lunn 41eace75cfSSrinivas Kandagatla struct nvmem_cell { 42eace75cfSSrinivas Kandagatla const char *name; 43eace75cfSSrinivas Kandagatla int offset; 44eace75cfSSrinivas Kandagatla int bytes; 45eace75cfSSrinivas Kandagatla int bit_offset; 46eace75cfSSrinivas Kandagatla int nbits; 47eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem; 48eace75cfSSrinivas Kandagatla struct list_head node; 49eace75cfSSrinivas Kandagatla }; 50eace75cfSSrinivas Kandagatla 51eace75cfSSrinivas Kandagatla static DEFINE_MUTEX(nvmem_mutex); 52eace75cfSSrinivas Kandagatla static DEFINE_IDA(nvmem_ida); 53eace75cfSSrinivas Kandagatla 54b985f4cbSBartosz Golaszewski static DEFINE_MUTEX(nvmem_cell_mutex); 55b985f4cbSBartosz Golaszewski static LIST_HEAD(nvmem_cell_tables); 56b985f4cbSBartosz Golaszewski 57506157beSBartosz Golaszewski static DEFINE_MUTEX(nvmem_lookup_mutex); 58506157beSBartosz Golaszewski static LIST_HEAD(nvmem_lookup_list); 59506157beSBartosz Golaszewski 60bee1138bSBartosz Golaszewski static BLOCKING_NOTIFIER_HEAD(nvmem_notifier); 61bee1138bSBartosz Golaszewski 62b6c217abSAndrew Lunn #ifdef CONFIG_DEBUG_LOCK_ALLOC 63b6c217abSAndrew Lunn static struct lock_class_key eeprom_lock_key; 64b6c217abSAndrew Lunn #endif 65b6c217abSAndrew Lunn 66eace75cfSSrinivas Kandagatla #define to_nvmem_device(d) container_of(d, struct nvmem_device, dev) 67795ddd18SSrinivas Kandagatla static int nvmem_reg_read(struct nvmem_device *nvmem, unsigned int offset, 68795ddd18SSrinivas Kandagatla void *val, size_t bytes) 69795ddd18SSrinivas Kandagatla { 70795ddd18SSrinivas Kandagatla if (nvmem->reg_read) 71795ddd18SSrinivas Kandagatla return nvmem->reg_read(nvmem->priv, offset, val, bytes); 72795ddd18SSrinivas Kandagatla 73795ddd18SSrinivas Kandagatla return -EINVAL; 74795ddd18SSrinivas Kandagatla } 75795ddd18SSrinivas Kandagatla 76795ddd18SSrinivas Kandagatla static int nvmem_reg_write(struct nvmem_device *nvmem, unsigned int offset, 77795ddd18SSrinivas Kandagatla void *val, size_t bytes) 78795ddd18SSrinivas Kandagatla { 79795ddd18SSrinivas Kandagatla if (nvmem->reg_write) 80795ddd18SSrinivas Kandagatla return nvmem->reg_write(nvmem->priv, offset, val, bytes); 81795ddd18SSrinivas Kandagatla 82795ddd18SSrinivas Kandagatla return -EINVAL; 83795ddd18SSrinivas Kandagatla } 84eace75cfSSrinivas Kandagatla 85eace75cfSSrinivas Kandagatla static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj, 86eace75cfSSrinivas Kandagatla struct bin_attribute *attr, 87eace75cfSSrinivas Kandagatla char *buf, loff_t pos, size_t count) 88eace75cfSSrinivas Kandagatla { 89b6c217abSAndrew Lunn struct device *dev; 90b6c217abSAndrew Lunn struct nvmem_device *nvmem; 91eace75cfSSrinivas Kandagatla int rc; 92eace75cfSSrinivas Kandagatla 93b6c217abSAndrew Lunn if (attr->private) 94b6c217abSAndrew Lunn dev = attr->private; 95b6c217abSAndrew Lunn else 96b6c217abSAndrew Lunn dev = container_of(kobj, struct device, kobj); 97b6c217abSAndrew Lunn nvmem = to_nvmem_device(dev); 98b6c217abSAndrew Lunn 99eace75cfSSrinivas Kandagatla /* Stop the user from reading */ 1007c806883SZhengShunQian if (pos >= nvmem->size) 101eace75cfSSrinivas Kandagatla return 0; 102eace75cfSSrinivas Kandagatla 103313a72ffSSrinivas Kandagatla if (count < nvmem->word_size) 104313a72ffSSrinivas Kandagatla return -EINVAL; 105313a72ffSSrinivas Kandagatla 106eace75cfSSrinivas Kandagatla if (pos + count > nvmem->size) 107eace75cfSSrinivas Kandagatla count = nvmem->size - pos; 108eace75cfSSrinivas Kandagatla 109eace75cfSSrinivas Kandagatla count = round_down(count, nvmem->word_size); 110eace75cfSSrinivas Kandagatla 111795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, pos, buf, count); 112eace75cfSSrinivas Kandagatla 113287980e4SArnd Bergmann if (rc) 114eace75cfSSrinivas Kandagatla return rc; 115eace75cfSSrinivas Kandagatla 116eace75cfSSrinivas Kandagatla return count; 117eace75cfSSrinivas Kandagatla } 118eace75cfSSrinivas Kandagatla 119eace75cfSSrinivas Kandagatla static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj, 120eace75cfSSrinivas Kandagatla struct bin_attribute *attr, 121eace75cfSSrinivas Kandagatla char *buf, loff_t pos, size_t count) 122eace75cfSSrinivas Kandagatla { 123b6c217abSAndrew Lunn struct device *dev; 124b6c217abSAndrew Lunn struct nvmem_device *nvmem; 125eace75cfSSrinivas Kandagatla int rc; 126eace75cfSSrinivas Kandagatla 127b6c217abSAndrew Lunn if (attr->private) 128b6c217abSAndrew Lunn dev = attr->private; 129b6c217abSAndrew Lunn else 130b6c217abSAndrew Lunn dev = container_of(kobj, struct device, kobj); 131b6c217abSAndrew Lunn nvmem = to_nvmem_device(dev); 132b6c217abSAndrew Lunn 133eace75cfSSrinivas Kandagatla /* Stop the user from writing */ 1347c806883SZhengShunQian if (pos >= nvmem->size) 13538b0774cSGuy Shapiro return -EFBIG; 136eace75cfSSrinivas Kandagatla 137313a72ffSSrinivas Kandagatla if (count < nvmem->word_size) 138313a72ffSSrinivas Kandagatla return -EINVAL; 139313a72ffSSrinivas Kandagatla 140eace75cfSSrinivas Kandagatla if (pos + count > nvmem->size) 141eace75cfSSrinivas Kandagatla count = nvmem->size - pos; 142eace75cfSSrinivas Kandagatla 143eace75cfSSrinivas Kandagatla count = round_down(count, nvmem->word_size); 144eace75cfSSrinivas Kandagatla 145795ddd18SSrinivas Kandagatla rc = nvmem_reg_write(nvmem, pos, buf, count); 146eace75cfSSrinivas Kandagatla 147287980e4SArnd Bergmann if (rc) 148eace75cfSSrinivas Kandagatla return rc; 149eace75cfSSrinivas Kandagatla 150eace75cfSSrinivas Kandagatla return count; 151eace75cfSSrinivas Kandagatla } 152eace75cfSSrinivas Kandagatla 153eace75cfSSrinivas Kandagatla /* default read/write permissions */ 154eace75cfSSrinivas Kandagatla static struct bin_attribute bin_attr_rw_nvmem = { 155eace75cfSSrinivas Kandagatla .attr = { 156eace75cfSSrinivas Kandagatla .name = "nvmem", 157e7e07f4fSBartosz Golaszewski .mode = 0644, 158eace75cfSSrinivas Kandagatla }, 159eace75cfSSrinivas Kandagatla .read = bin_attr_nvmem_read, 160eace75cfSSrinivas Kandagatla .write = bin_attr_nvmem_write, 161eace75cfSSrinivas Kandagatla }; 162eace75cfSSrinivas Kandagatla 163eace75cfSSrinivas Kandagatla static struct bin_attribute *nvmem_bin_rw_attributes[] = { 164eace75cfSSrinivas Kandagatla &bin_attr_rw_nvmem, 165eace75cfSSrinivas Kandagatla NULL, 166eace75cfSSrinivas Kandagatla }; 167eace75cfSSrinivas Kandagatla 168eace75cfSSrinivas Kandagatla static const struct attribute_group nvmem_bin_rw_group = { 169eace75cfSSrinivas Kandagatla .bin_attrs = nvmem_bin_rw_attributes, 170eace75cfSSrinivas Kandagatla }; 171eace75cfSSrinivas Kandagatla 172eace75cfSSrinivas Kandagatla static const struct attribute_group *nvmem_rw_dev_groups[] = { 173eace75cfSSrinivas Kandagatla &nvmem_bin_rw_group, 174eace75cfSSrinivas Kandagatla NULL, 175eace75cfSSrinivas Kandagatla }; 176eace75cfSSrinivas Kandagatla 177eace75cfSSrinivas Kandagatla /* read only permission */ 178eace75cfSSrinivas Kandagatla static struct bin_attribute bin_attr_ro_nvmem = { 179eace75cfSSrinivas Kandagatla .attr = { 180eace75cfSSrinivas Kandagatla .name = "nvmem", 181e7e07f4fSBartosz Golaszewski .mode = 0444, 182eace75cfSSrinivas Kandagatla }, 183eace75cfSSrinivas Kandagatla .read = bin_attr_nvmem_read, 184eace75cfSSrinivas Kandagatla }; 185eace75cfSSrinivas Kandagatla 186eace75cfSSrinivas Kandagatla static struct bin_attribute *nvmem_bin_ro_attributes[] = { 187eace75cfSSrinivas Kandagatla &bin_attr_ro_nvmem, 188eace75cfSSrinivas Kandagatla NULL, 189eace75cfSSrinivas Kandagatla }; 190eace75cfSSrinivas Kandagatla 191eace75cfSSrinivas Kandagatla static const struct attribute_group nvmem_bin_ro_group = { 192eace75cfSSrinivas Kandagatla .bin_attrs = nvmem_bin_ro_attributes, 193eace75cfSSrinivas Kandagatla }; 194eace75cfSSrinivas Kandagatla 195eace75cfSSrinivas Kandagatla static const struct attribute_group *nvmem_ro_dev_groups[] = { 196eace75cfSSrinivas Kandagatla &nvmem_bin_ro_group, 197eace75cfSSrinivas Kandagatla NULL, 198eace75cfSSrinivas Kandagatla }; 199eace75cfSSrinivas Kandagatla 200811b0d65SAndrew Lunn /* default read/write permissions, root only */ 201811b0d65SAndrew Lunn static struct bin_attribute bin_attr_rw_root_nvmem = { 202811b0d65SAndrew Lunn .attr = { 203811b0d65SAndrew Lunn .name = "nvmem", 204e7e07f4fSBartosz Golaszewski .mode = 0600, 205811b0d65SAndrew Lunn }, 206811b0d65SAndrew Lunn .read = bin_attr_nvmem_read, 207811b0d65SAndrew Lunn .write = bin_attr_nvmem_write, 208811b0d65SAndrew Lunn }; 209811b0d65SAndrew Lunn 210811b0d65SAndrew Lunn static struct bin_attribute *nvmem_bin_rw_root_attributes[] = { 211811b0d65SAndrew Lunn &bin_attr_rw_root_nvmem, 212811b0d65SAndrew Lunn NULL, 213811b0d65SAndrew Lunn }; 214811b0d65SAndrew Lunn 215811b0d65SAndrew Lunn static const struct attribute_group nvmem_bin_rw_root_group = { 216811b0d65SAndrew Lunn .bin_attrs = nvmem_bin_rw_root_attributes, 217811b0d65SAndrew Lunn }; 218811b0d65SAndrew Lunn 219811b0d65SAndrew Lunn static const struct attribute_group *nvmem_rw_root_dev_groups[] = { 220811b0d65SAndrew Lunn &nvmem_bin_rw_root_group, 221811b0d65SAndrew Lunn NULL, 222811b0d65SAndrew Lunn }; 223811b0d65SAndrew Lunn 224811b0d65SAndrew Lunn /* read only permission, root only */ 225811b0d65SAndrew Lunn static struct bin_attribute bin_attr_ro_root_nvmem = { 226811b0d65SAndrew Lunn .attr = { 227811b0d65SAndrew Lunn .name = "nvmem", 228e7e07f4fSBartosz Golaszewski .mode = 0400, 229811b0d65SAndrew Lunn }, 230811b0d65SAndrew Lunn .read = bin_attr_nvmem_read, 231811b0d65SAndrew Lunn }; 232811b0d65SAndrew Lunn 233811b0d65SAndrew Lunn static struct bin_attribute *nvmem_bin_ro_root_attributes[] = { 234811b0d65SAndrew Lunn &bin_attr_ro_root_nvmem, 235811b0d65SAndrew Lunn NULL, 236811b0d65SAndrew Lunn }; 237811b0d65SAndrew Lunn 238811b0d65SAndrew Lunn static const struct attribute_group nvmem_bin_ro_root_group = { 239811b0d65SAndrew Lunn .bin_attrs = nvmem_bin_ro_root_attributes, 240811b0d65SAndrew Lunn }; 241811b0d65SAndrew Lunn 242811b0d65SAndrew Lunn static const struct attribute_group *nvmem_ro_root_dev_groups[] = { 243811b0d65SAndrew Lunn &nvmem_bin_ro_root_group, 244811b0d65SAndrew Lunn NULL, 245811b0d65SAndrew Lunn }; 246811b0d65SAndrew Lunn 247eace75cfSSrinivas Kandagatla static void nvmem_release(struct device *dev) 248eace75cfSSrinivas Kandagatla { 249eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem = to_nvmem_device(dev); 250eace75cfSSrinivas Kandagatla 251eace75cfSSrinivas Kandagatla ida_simple_remove(&nvmem_ida, nvmem->id); 252eace75cfSSrinivas Kandagatla kfree(nvmem); 253eace75cfSSrinivas Kandagatla } 254eace75cfSSrinivas Kandagatla 255eace75cfSSrinivas Kandagatla static const struct device_type nvmem_provider_type = { 256eace75cfSSrinivas Kandagatla .release = nvmem_release, 257eace75cfSSrinivas Kandagatla }; 258eace75cfSSrinivas Kandagatla 259eace75cfSSrinivas Kandagatla static struct bus_type nvmem_bus_type = { 260eace75cfSSrinivas Kandagatla .name = "nvmem", 261eace75cfSSrinivas Kandagatla }; 262eace75cfSSrinivas Kandagatla 263eace75cfSSrinivas Kandagatla static int of_nvmem_match(struct device *dev, void *nvmem_np) 264eace75cfSSrinivas Kandagatla { 265eace75cfSSrinivas Kandagatla return dev->of_node == nvmem_np; 266eace75cfSSrinivas Kandagatla } 267eace75cfSSrinivas Kandagatla 268eace75cfSSrinivas Kandagatla static struct nvmem_device *of_nvmem_find(struct device_node *nvmem_np) 269eace75cfSSrinivas Kandagatla { 270eace75cfSSrinivas Kandagatla struct device *d; 271eace75cfSSrinivas Kandagatla 272eace75cfSSrinivas Kandagatla if (!nvmem_np) 273eace75cfSSrinivas Kandagatla return NULL; 274eace75cfSSrinivas Kandagatla 275eace75cfSSrinivas Kandagatla d = bus_find_device(&nvmem_bus_type, NULL, nvmem_np, of_nvmem_match); 276eace75cfSSrinivas Kandagatla 277eace75cfSSrinivas Kandagatla if (!d) 278eace75cfSSrinivas Kandagatla return NULL; 279eace75cfSSrinivas Kandagatla 280eace75cfSSrinivas Kandagatla return to_nvmem_device(d); 281eace75cfSSrinivas Kandagatla } 282eace75cfSSrinivas Kandagatla 283506157beSBartosz Golaszewski static struct nvmem_device *nvmem_find(const char *name) 284506157beSBartosz Golaszewski { 285506157beSBartosz Golaszewski struct device *d; 286506157beSBartosz Golaszewski 287506157beSBartosz Golaszewski d = bus_find_device_by_name(&nvmem_bus_type, NULL, name); 288506157beSBartosz Golaszewski 289506157beSBartosz Golaszewski if (!d) 290506157beSBartosz Golaszewski return NULL; 291506157beSBartosz Golaszewski 292506157beSBartosz Golaszewski return to_nvmem_device(d); 293506157beSBartosz Golaszewski } 294506157beSBartosz Golaszewski 295eace75cfSSrinivas Kandagatla static void nvmem_cell_drop(struct nvmem_cell *cell) 296eace75cfSSrinivas Kandagatla { 297bee1138bSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_REMOVE, cell); 298c7235ee3SBartosz Golaszewski mutex_lock(&nvmem_mutex); 299eace75cfSSrinivas Kandagatla list_del(&cell->node); 300c7235ee3SBartosz Golaszewski mutex_unlock(&nvmem_mutex); 301*badcdff1SRob Herring kfree(cell->name); 302eace75cfSSrinivas Kandagatla kfree(cell); 303eace75cfSSrinivas Kandagatla } 304eace75cfSSrinivas Kandagatla 305eace75cfSSrinivas Kandagatla static void nvmem_device_remove_all_cells(const struct nvmem_device *nvmem) 306eace75cfSSrinivas Kandagatla { 3071852183eSBartosz Golaszewski struct nvmem_cell *cell, *p; 308eace75cfSSrinivas Kandagatla 309c7235ee3SBartosz Golaszewski list_for_each_entry_safe(cell, p, &nvmem->cells, node) 310eace75cfSSrinivas Kandagatla nvmem_cell_drop(cell); 311eace75cfSSrinivas Kandagatla } 312eace75cfSSrinivas Kandagatla 313eace75cfSSrinivas Kandagatla static void nvmem_cell_add(struct nvmem_cell *cell) 314eace75cfSSrinivas Kandagatla { 315c7235ee3SBartosz Golaszewski mutex_lock(&nvmem_mutex); 316c7235ee3SBartosz Golaszewski list_add_tail(&cell->node, &cell->nvmem->cells); 317c7235ee3SBartosz Golaszewski mutex_unlock(&nvmem_mutex); 318bee1138bSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_ADD, cell); 319eace75cfSSrinivas Kandagatla } 320eace75cfSSrinivas Kandagatla 321eace75cfSSrinivas Kandagatla static int nvmem_cell_info_to_nvmem_cell(struct nvmem_device *nvmem, 322eace75cfSSrinivas Kandagatla const struct nvmem_cell_info *info, 323eace75cfSSrinivas Kandagatla struct nvmem_cell *cell) 324eace75cfSSrinivas Kandagatla { 325eace75cfSSrinivas Kandagatla cell->nvmem = nvmem; 326eace75cfSSrinivas Kandagatla cell->offset = info->offset; 327eace75cfSSrinivas Kandagatla cell->bytes = info->bytes; 328eace75cfSSrinivas Kandagatla cell->name = info->name; 329eace75cfSSrinivas Kandagatla 330eace75cfSSrinivas Kandagatla cell->bit_offset = info->bit_offset; 331eace75cfSSrinivas Kandagatla cell->nbits = info->nbits; 332eace75cfSSrinivas Kandagatla 333eace75cfSSrinivas Kandagatla if (cell->nbits) 334eace75cfSSrinivas Kandagatla cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset, 335eace75cfSSrinivas Kandagatla BITS_PER_BYTE); 336eace75cfSSrinivas Kandagatla 337eace75cfSSrinivas Kandagatla if (!IS_ALIGNED(cell->offset, nvmem->stride)) { 338eace75cfSSrinivas Kandagatla dev_err(&nvmem->dev, 339eace75cfSSrinivas Kandagatla "cell %s unaligned to nvmem stride %d\n", 340eace75cfSSrinivas Kandagatla cell->name, nvmem->stride); 341eace75cfSSrinivas Kandagatla return -EINVAL; 342eace75cfSSrinivas Kandagatla } 343eace75cfSSrinivas Kandagatla 344eace75cfSSrinivas Kandagatla return 0; 345eace75cfSSrinivas Kandagatla } 346eace75cfSSrinivas Kandagatla 347b3db17e4SAndrew Lunn /** 348b3db17e4SAndrew Lunn * nvmem_add_cells() - Add cell information to an nvmem device 349b3db17e4SAndrew Lunn * 350b3db17e4SAndrew Lunn * @nvmem: nvmem device to add cells to. 351b3db17e4SAndrew Lunn * @info: nvmem cell info to add to the device 352b3db17e4SAndrew Lunn * @ncells: number of cells in info 353b3db17e4SAndrew Lunn * 354b3db17e4SAndrew Lunn * Return: 0 or negative error code on failure. 355b3db17e4SAndrew Lunn */ 356ef92ab30SSrinivas Kandagatla static int nvmem_add_cells(struct nvmem_device *nvmem, 357b3db17e4SAndrew Lunn const struct nvmem_cell_info *info, 358b3db17e4SAndrew Lunn int ncells) 359eace75cfSSrinivas Kandagatla { 360eace75cfSSrinivas Kandagatla struct nvmem_cell **cells; 361eace75cfSSrinivas Kandagatla int i, rval; 362eace75cfSSrinivas Kandagatla 363b3db17e4SAndrew Lunn cells = kcalloc(ncells, sizeof(*cells), GFP_KERNEL); 364eace75cfSSrinivas Kandagatla if (!cells) 365eace75cfSSrinivas Kandagatla return -ENOMEM; 366eace75cfSSrinivas Kandagatla 367b3db17e4SAndrew Lunn for (i = 0; i < ncells; i++) { 368eace75cfSSrinivas Kandagatla cells[i] = kzalloc(sizeof(**cells), GFP_KERNEL); 369eace75cfSSrinivas Kandagatla if (!cells[i]) { 370eace75cfSSrinivas Kandagatla rval = -ENOMEM; 371eace75cfSSrinivas Kandagatla goto err; 372eace75cfSSrinivas Kandagatla } 373eace75cfSSrinivas Kandagatla 374eace75cfSSrinivas Kandagatla rval = nvmem_cell_info_to_nvmem_cell(nvmem, &info[i], cells[i]); 375287980e4SArnd Bergmann if (rval) { 376eace75cfSSrinivas Kandagatla kfree(cells[i]); 377eace75cfSSrinivas Kandagatla goto err; 378eace75cfSSrinivas Kandagatla } 379eace75cfSSrinivas Kandagatla 380eace75cfSSrinivas Kandagatla nvmem_cell_add(cells[i]); 381eace75cfSSrinivas Kandagatla } 382eace75cfSSrinivas Kandagatla 383eace75cfSSrinivas Kandagatla /* remove tmp array */ 384eace75cfSSrinivas Kandagatla kfree(cells); 385eace75cfSSrinivas Kandagatla 386eace75cfSSrinivas Kandagatla return 0; 387eace75cfSSrinivas Kandagatla err: 388dfdf1414SRasmus Villemoes while (i--) 389eace75cfSSrinivas Kandagatla nvmem_cell_drop(cells[i]); 390eace75cfSSrinivas Kandagatla 391dfdf1414SRasmus Villemoes kfree(cells); 392dfdf1414SRasmus Villemoes 393eace75cfSSrinivas Kandagatla return rval; 394eace75cfSSrinivas Kandagatla } 395eace75cfSSrinivas Kandagatla 396b6c217abSAndrew Lunn /* 397b6c217abSAndrew Lunn * nvmem_setup_compat() - Create an additional binary entry in 398b6c217abSAndrew Lunn * drivers sys directory, to be backwards compatible with the older 399b6c217abSAndrew Lunn * drivers/misc/eeprom drivers. 400b6c217abSAndrew Lunn */ 401b6c217abSAndrew Lunn static int nvmem_setup_compat(struct nvmem_device *nvmem, 402b6c217abSAndrew Lunn const struct nvmem_config *config) 403b6c217abSAndrew Lunn { 404b6c217abSAndrew Lunn int rval; 405b6c217abSAndrew Lunn 406b6c217abSAndrew Lunn if (!config->base_dev) 407b6c217abSAndrew Lunn return -EINVAL; 408b6c217abSAndrew Lunn 409b6c217abSAndrew Lunn if (nvmem->read_only) 410b6c217abSAndrew Lunn nvmem->eeprom = bin_attr_ro_root_nvmem; 411b6c217abSAndrew Lunn else 412b6c217abSAndrew Lunn nvmem->eeprom = bin_attr_rw_root_nvmem; 413b6c217abSAndrew Lunn nvmem->eeprom.attr.name = "eeprom"; 414b6c217abSAndrew Lunn nvmem->eeprom.size = nvmem->size; 415b6c217abSAndrew Lunn #ifdef CONFIG_DEBUG_LOCK_ALLOC 416b6c217abSAndrew Lunn nvmem->eeprom.attr.key = &eeprom_lock_key; 417b6c217abSAndrew Lunn #endif 418b6c217abSAndrew Lunn nvmem->eeprom.private = &nvmem->dev; 419b6c217abSAndrew Lunn nvmem->base_dev = config->base_dev; 420b6c217abSAndrew Lunn 421b6c217abSAndrew Lunn rval = device_create_bin_file(nvmem->base_dev, &nvmem->eeprom); 422b6c217abSAndrew Lunn if (rval) { 423b6c217abSAndrew Lunn dev_err(&nvmem->dev, 424b6c217abSAndrew Lunn "Failed to create eeprom binary file %d\n", rval); 425b6c217abSAndrew Lunn return rval; 426b6c217abSAndrew Lunn } 427b6c217abSAndrew Lunn 428b6c217abSAndrew Lunn nvmem->flags |= FLAG_COMPAT; 429b6c217abSAndrew Lunn 430b6c217abSAndrew Lunn return 0; 431b6c217abSAndrew Lunn } 432b6c217abSAndrew Lunn 433bee1138bSBartosz Golaszewski /** 434bee1138bSBartosz Golaszewski * nvmem_register_notifier() - Register a notifier block for nvmem events. 435bee1138bSBartosz Golaszewski * 436bee1138bSBartosz Golaszewski * @nb: notifier block to be called on nvmem events. 437bee1138bSBartosz Golaszewski * 438bee1138bSBartosz Golaszewski * Return: 0 on success, negative error number on failure. 439bee1138bSBartosz Golaszewski */ 440bee1138bSBartosz Golaszewski int nvmem_register_notifier(struct notifier_block *nb) 441bee1138bSBartosz Golaszewski { 442bee1138bSBartosz Golaszewski return blocking_notifier_chain_register(&nvmem_notifier, nb); 443bee1138bSBartosz Golaszewski } 444bee1138bSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_register_notifier); 445bee1138bSBartosz Golaszewski 446bee1138bSBartosz Golaszewski /** 447bee1138bSBartosz Golaszewski * nvmem_unregister_notifier() - Unregister a notifier block for nvmem events. 448bee1138bSBartosz Golaszewski * 449bee1138bSBartosz Golaszewski * @nb: notifier block to be unregistered. 450bee1138bSBartosz Golaszewski * 451bee1138bSBartosz Golaszewski * Return: 0 on success, negative error number on failure. 452bee1138bSBartosz Golaszewski */ 453bee1138bSBartosz Golaszewski int nvmem_unregister_notifier(struct notifier_block *nb) 454bee1138bSBartosz Golaszewski { 455bee1138bSBartosz Golaszewski return blocking_notifier_chain_unregister(&nvmem_notifier, nb); 456bee1138bSBartosz Golaszewski } 457bee1138bSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_unregister_notifier); 458bee1138bSBartosz Golaszewski 459b985f4cbSBartosz Golaszewski static int nvmem_add_cells_from_table(struct nvmem_device *nvmem) 460b985f4cbSBartosz Golaszewski { 461b985f4cbSBartosz Golaszewski const struct nvmem_cell_info *info; 462b985f4cbSBartosz Golaszewski struct nvmem_cell_table *table; 463b985f4cbSBartosz Golaszewski struct nvmem_cell *cell; 464b985f4cbSBartosz Golaszewski int rval = 0, i; 465b985f4cbSBartosz Golaszewski 466b985f4cbSBartosz Golaszewski mutex_lock(&nvmem_cell_mutex); 467b985f4cbSBartosz Golaszewski list_for_each_entry(table, &nvmem_cell_tables, node) { 468b985f4cbSBartosz Golaszewski if (strcmp(nvmem_dev_name(nvmem), table->nvmem_name) == 0) { 469b985f4cbSBartosz Golaszewski for (i = 0; i < table->ncells; i++) { 470b985f4cbSBartosz Golaszewski info = &table->cells[i]; 471b985f4cbSBartosz Golaszewski 472b985f4cbSBartosz Golaszewski cell = kzalloc(sizeof(*cell), GFP_KERNEL); 473b985f4cbSBartosz Golaszewski if (!cell) { 474b985f4cbSBartosz Golaszewski rval = -ENOMEM; 475b985f4cbSBartosz Golaszewski goto out; 476b985f4cbSBartosz Golaszewski } 477b985f4cbSBartosz Golaszewski 478b985f4cbSBartosz Golaszewski rval = nvmem_cell_info_to_nvmem_cell(nvmem, 479b985f4cbSBartosz Golaszewski info, 480b985f4cbSBartosz Golaszewski cell); 481b985f4cbSBartosz Golaszewski if (rval) { 482b985f4cbSBartosz Golaszewski kfree(cell); 483b985f4cbSBartosz Golaszewski goto out; 484b985f4cbSBartosz Golaszewski } 485b985f4cbSBartosz Golaszewski 486b985f4cbSBartosz Golaszewski nvmem_cell_add(cell); 487b985f4cbSBartosz Golaszewski } 488b985f4cbSBartosz Golaszewski } 489b985f4cbSBartosz Golaszewski } 490b985f4cbSBartosz Golaszewski 491b985f4cbSBartosz Golaszewski out: 492b985f4cbSBartosz Golaszewski mutex_unlock(&nvmem_cell_mutex); 493b985f4cbSBartosz Golaszewski return rval; 494b985f4cbSBartosz Golaszewski } 495b985f4cbSBartosz Golaszewski 496e888d445SBartosz Golaszewski static struct nvmem_cell * 497e888d445SBartosz Golaszewski nvmem_find_cell_by_index(struct nvmem_device *nvmem, int index) 498e888d445SBartosz Golaszewski { 499e888d445SBartosz Golaszewski struct nvmem_cell *cell = NULL; 500e888d445SBartosz Golaszewski int i = 0; 501e888d445SBartosz Golaszewski 502e888d445SBartosz Golaszewski mutex_lock(&nvmem_mutex); 503e888d445SBartosz Golaszewski list_for_each_entry(cell, &nvmem->cells, node) { 504e888d445SBartosz Golaszewski if (index == i++) 505e888d445SBartosz Golaszewski break; 506e888d445SBartosz Golaszewski } 507e888d445SBartosz Golaszewski mutex_unlock(&nvmem_mutex); 508e888d445SBartosz Golaszewski 509e888d445SBartosz Golaszewski return cell; 510e888d445SBartosz Golaszewski } 511e888d445SBartosz Golaszewski 512506157beSBartosz Golaszewski static struct nvmem_cell * 513506157beSBartosz Golaszewski nvmem_find_cell_by_name(struct nvmem_device *nvmem, const char *cell_id) 514506157beSBartosz Golaszewski { 515506157beSBartosz Golaszewski struct nvmem_cell *cell = NULL; 516506157beSBartosz Golaszewski 517506157beSBartosz Golaszewski mutex_lock(&nvmem_mutex); 518506157beSBartosz Golaszewski list_for_each_entry(cell, &nvmem->cells, node) { 519506157beSBartosz Golaszewski if (strcmp(cell_id, cell->name) == 0) 520506157beSBartosz Golaszewski break; 521506157beSBartosz Golaszewski } 522506157beSBartosz Golaszewski mutex_unlock(&nvmem_mutex); 523506157beSBartosz Golaszewski 524506157beSBartosz Golaszewski return cell; 525506157beSBartosz Golaszewski } 526506157beSBartosz Golaszewski 527e888d445SBartosz Golaszewski static int nvmem_add_cells_from_of(struct nvmem_device *nvmem) 528e888d445SBartosz Golaszewski { 529e888d445SBartosz Golaszewski struct device_node *parent, *child; 530e888d445SBartosz Golaszewski struct device *dev = &nvmem->dev; 531e888d445SBartosz Golaszewski struct nvmem_cell *cell; 532e888d445SBartosz Golaszewski const __be32 *addr; 533e888d445SBartosz Golaszewski int len; 534e888d445SBartosz Golaszewski 535e888d445SBartosz Golaszewski parent = dev->of_node; 536e888d445SBartosz Golaszewski 537e888d445SBartosz Golaszewski for_each_child_of_node(parent, child) { 538e888d445SBartosz Golaszewski addr = of_get_property(child, "reg", &len); 539e888d445SBartosz Golaszewski if (!addr || (len < 2 * sizeof(u32))) { 540e888d445SBartosz Golaszewski dev_err(dev, "nvmem: invalid reg on %pOF\n", child); 541e888d445SBartosz Golaszewski return -EINVAL; 542e888d445SBartosz Golaszewski } 543e888d445SBartosz Golaszewski 544e888d445SBartosz Golaszewski cell = kzalloc(sizeof(*cell), GFP_KERNEL); 545e888d445SBartosz Golaszewski if (!cell) 546e888d445SBartosz Golaszewski return -ENOMEM; 547e888d445SBartosz Golaszewski 548e888d445SBartosz Golaszewski cell->nvmem = nvmem; 549e888d445SBartosz Golaszewski cell->offset = be32_to_cpup(addr++); 550e888d445SBartosz Golaszewski cell->bytes = be32_to_cpup(addr); 551*badcdff1SRob Herring cell->name = kasprintf(GFP_KERNEL, "%pOFn", child); 552e888d445SBartosz Golaszewski 553e888d445SBartosz Golaszewski addr = of_get_property(child, "bits", &len); 554e888d445SBartosz Golaszewski if (addr && len == (2 * sizeof(u32))) { 555e888d445SBartosz Golaszewski cell->bit_offset = be32_to_cpup(addr++); 556e888d445SBartosz Golaszewski cell->nbits = be32_to_cpup(addr); 557e888d445SBartosz Golaszewski } 558e888d445SBartosz Golaszewski 559e888d445SBartosz Golaszewski if (cell->nbits) 560e888d445SBartosz Golaszewski cell->bytes = DIV_ROUND_UP( 561e888d445SBartosz Golaszewski cell->nbits + cell->bit_offset, 562e888d445SBartosz Golaszewski BITS_PER_BYTE); 563e888d445SBartosz Golaszewski 564e888d445SBartosz Golaszewski if (!IS_ALIGNED(cell->offset, nvmem->stride)) { 565e888d445SBartosz Golaszewski dev_err(dev, "cell %s unaligned to nvmem stride %d\n", 566e888d445SBartosz Golaszewski cell->name, nvmem->stride); 567e888d445SBartosz Golaszewski /* Cells already added will be freed later. */ 568*badcdff1SRob Herring kfree(cell->name); 569e888d445SBartosz Golaszewski kfree(cell); 570e888d445SBartosz Golaszewski return -EINVAL; 571e888d445SBartosz Golaszewski } 572e888d445SBartosz Golaszewski 573e888d445SBartosz Golaszewski nvmem_cell_add(cell); 574e888d445SBartosz Golaszewski } 575e888d445SBartosz Golaszewski 576e888d445SBartosz Golaszewski return 0; 577e888d445SBartosz Golaszewski } 578e888d445SBartosz Golaszewski 579eace75cfSSrinivas Kandagatla /** 580eace75cfSSrinivas Kandagatla * nvmem_register() - Register a nvmem device for given nvmem_config. 581eace75cfSSrinivas Kandagatla * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem 582eace75cfSSrinivas Kandagatla * 583eace75cfSSrinivas Kandagatla * @config: nvmem device configuration with which nvmem device is created. 584eace75cfSSrinivas Kandagatla * 585eace75cfSSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device 586eace75cfSSrinivas Kandagatla * on success. 587eace75cfSSrinivas Kandagatla */ 588eace75cfSSrinivas Kandagatla 589eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem_register(const struct nvmem_config *config) 590eace75cfSSrinivas Kandagatla { 591eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem; 592eace75cfSSrinivas Kandagatla int rval; 593eace75cfSSrinivas Kandagatla 594eace75cfSSrinivas Kandagatla if (!config->dev) 595eace75cfSSrinivas Kandagatla return ERR_PTR(-EINVAL); 596eace75cfSSrinivas Kandagatla 597eace75cfSSrinivas Kandagatla nvmem = kzalloc(sizeof(*nvmem), GFP_KERNEL); 598eace75cfSSrinivas Kandagatla if (!nvmem) 599eace75cfSSrinivas Kandagatla return ERR_PTR(-ENOMEM); 600eace75cfSSrinivas Kandagatla 601eace75cfSSrinivas Kandagatla rval = ida_simple_get(&nvmem_ida, 0, 0, GFP_KERNEL); 602eace75cfSSrinivas Kandagatla if (rval < 0) { 603eace75cfSSrinivas Kandagatla kfree(nvmem); 604eace75cfSSrinivas Kandagatla return ERR_PTR(rval); 605eace75cfSSrinivas Kandagatla } 606eace75cfSSrinivas Kandagatla 607c1de7f43SBartosz Golaszewski kref_init(&nvmem->refcnt); 608c7235ee3SBartosz Golaszewski INIT_LIST_HEAD(&nvmem->cells); 609c1de7f43SBartosz Golaszewski 610eace75cfSSrinivas Kandagatla nvmem->id = rval; 611eace75cfSSrinivas Kandagatla nvmem->owner = config->owner; 61217eb18d6SMasahiro Yamada if (!nvmem->owner && config->dev->driver) 61317eb18d6SMasahiro Yamada nvmem->owner = config->dev->driver->owner; 61499897efdSHeiner Kallweit nvmem->stride = config->stride ?: 1; 61599897efdSHeiner Kallweit nvmem->word_size = config->word_size ?: 1; 616795ddd18SSrinivas Kandagatla nvmem->size = config->size; 617eace75cfSSrinivas Kandagatla nvmem->dev.type = &nvmem_provider_type; 618eace75cfSSrinivas Kandagatla nvmem->dev.bus = &nvmem_bus_type; 619eace75cfSSrinivas Kandagatla nvmem->dev.parent = config->dev; 620795ddd18SSrinivas Kandagatla nvmem->priv = config->priv; 621795ddd18SSrinivas Kandagatla nvmem->reg_read = config->reg_read; 622795ddd18SSrinivas Kandagatla nvmem->reg_write = config->reg_write; 623fc2f9970SHeiner Kallweit nvmem->dev.of_node = config->dev->of_node; 624fd0f4906SAndrey Smirnov 625fd0f4906SAndrey Smirnov if (config->id == -1 && config->name) { 626fd0f4906SAndrey Smirnov dev_set_name(&nvmem->dev, "%s", config->name); 627fd0f4906SAndrey Smirnov } else { 628eace75cfSSrinivas Kandagatla dev_set_name(&nvmem->dev, "%s%d", 6295253193dSAban Bedel config->name ? : "nvmem", 6305253193dSAban Bedel config->name ? config->id : nvmem->id); 631fd0f4906SAndrey Smirnov } 632eace75cfSSrinivas Kandagatla 633fc2f9970SHeiner Kallweit nvmem->read_only = device_property_present(config->dev, "read-only") | 634eace75cfSSrinivas Kandagatla config->read_only; 635eace75cfSSrinivas Kandagatla 636811b0d65SAndrew Lunn if (config->root_only) 637811b0d65SAndrew Lunn nvmem->dev.groups = nvmem->read_only ? 638811b0d65SAndrew Lunn nvmem_ro_root_dev_groups : 639811b0d65SAndrew Lunn nvmem_rw_root_dev_groups; 640811b0d65SAndrew Lunn else 641811b0d65SAndrew Lunn nvmem->dev.groups = nvmem->read_only ? 642811b0d65SAndrew Lunn nvmem_ro_dev_groups : 643eace75cfSSrinivas Kandagatla nvmem_rw_dev_groups; 644eace75cfSSrinivas Kandagatla 645eace75cfSSrinivas Kandagatla device_initialize(&nvmem->dev); 646eace75cfSSrinivas Kandagatla 647eace75cfSSrinivas Kandagatla dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name); 648eace75cfSSrinivas Kandagatla 649eace75cfSSrinivas Kandagatla rval = device_add(&nvmem->dev); 650b6c217abSAndrew Lunn if (rval) 6513360acdfSJohan Hovold goto err_put_device; 652b6c217abSAndrew Lunn 653b6c217abSAndrew Lunn if (config->compat) { 654b6c217abSAndrew Lunn rval = nvmem_setup_compat(nvmem, config); 655b6c217abSAndrew Lunn if (rval) 6563360acdfSJohan Hovold goto err_device_del; 657eace75cfSSrinivas Kandagatla } 658eace75cfSSrinivas Kandagatla 659fa72d847SBartosz Golaszewski if (config->cells) { 660fa72d847SBartosz Golaszewski rval = nvmem_add_cells(nvmem, config->cells, config->ncells); 661fa72d847SBartosz Golaszewski if (rval) 662fa72d847SBartosz Golaszewski goto err_teardown_compat; 663fa72d847SBartosz Golaszewski } 664eace75cfSSrinivas Kandagatla 665b985f4cbSBartosz Golaszewski rval = nvmem_add_cells_from_table(nvmem); 666b985f4cbSBartosz Golaszewski if (rval) 667b985f4cbSBartosz Golaszewski goto err_remove_cells; 668b985f4cbSBartosz Golaszewski 669e888d445SBartosz Golaszewski rval = nvmem_add_cells_from_of(nvmem); 670e888d445SBartosz Golaszewski if (rval) 671e888d445SBartosz Golaszewski goto err_remove_cells; 672e888d445SBartosz Golaszewski 673bee1138bSBartosz Golaszewski rval = blocking_notifier_call_chain(&nvmem_notifier, NVMEM_ADD, nvmem); 674bee1138bSBartosz Golaszewski if (rval) 675bee1138bSBartosz Golaszewski goto err_remove_cells; 676bee1138bSBartosz Golaszewski 677eace75cfSSrinivas Kandagatla return nvmem; 6783360acdfSJohan Hovold 679b985f4cbSBartosz Golaszewski err_remove_cells: 680b985f4cbSBartosz Golaszewski nvmem_device_remove_all_cells(nvmem); 681fa72d847SBartosz Golaszewski err_teardown_compat: 682fa72d847SBartosz Golaszewski if (config->compat) 683fa72d847SBartosz Golaszewski device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); 6843360acdfSJohan Hovold err_device_del: 6853360acdfSJohan Hovold device_del(&nvmem->dev); 6863360acdfSJohan Hovold err_put_device: 6873360acdfSJohan Hovold put_device(&nvmem->dev); 6883360acdfSJohan Hovold 689b6c217abSAndrew Lunn return ERR_PTR(rval); 690eace75cfSSrinivas Kandagatla } 691eace75cfSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_register); 692eace75cfSSrinivas Kandagatla 693c1de7f43SBartosz Golaszewski static void nvmem_device_release(struct kref *kref) 694c1de7f43SBartosz Golaszewski { 695c1de7f43SBartosz Golaszewski struct nvmem_device *nvmem; 696c1de7f43SBartosz Golaszewski 697c1de7f43SBartosz Golaszewski nvmem = container_of(kref, struct nvmem_device, refcnt); 698c1de7f43SBartosz Golaszewski 699bee1138bSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_REMOVE, nvmem); 700bee1138bSBartosz Golaszewski 701c1de7f43SBartosz Golaszewski if (nvmem->flags & FLAG_COMPAT) 702c1de7f43SBartosz Golaszewski device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); 703c1de7f43SBartosz Golaszewski 704c1de7f43SBartosz Golaszewski nvmem_device_remove_all_cells(nvmem); 705c1de7f43SBartosz Golaszewski device_del(&nvmem->dev); 706c1de7f43SBartosz Golaszewski put_device(&nvmem->dev); 707c1de7f43SBartosz Golaszewski } 708c1de7f43SBartosz Golaszewski 709eace75cfSSrinivas Kandagatla /** 710eace75cfSSrinivas Kandagatla * nvmem_unregister() - Unregister previously registered nvmem device 711eace75cfSSrinivas Kandagatla * 712eace75cfSSrinivas Kandagatla * @nvmem: Pointer to previously registered nvmem device. 713eace75cfSSrinivas Kandagatla */ 714bf58e882SBartosz Golaszewski void nvmem_unregister(struct nvmem_device *nvmem) 715eace75cfSSrinivas Kandagatla { 716c1de7f43SBartosz Golaszewski kref_put(&nvmem->refcnt, nvmem_device_release); 717eace75cfSSrinivas Kandagatla } 718eace75cfSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_unregister); 719eace75cfSSrinivas Kandagatla 720f1f50ecaSAndrey Smirnov static void devm_nvmem_release(struct device *dev, void *res) 721f1f50ecaSAndrey Smirnov { 722bf58e882SBartosz Golaszewski nvmem_unregister(*(struct nvmem_device **)res); 723f1f50ecaSAndrey Smirnov } 724f1f50ecaSAndrey Smirnov 725f1f50ecaSAndrey Smirnov /** 726f1f50ecaSAndrey Smirnov * devm_nvmem_register() - Register a managed nvmem device for given 727f1f50ecaSAndrey Smirnov * nvmem_config. 728f1f50ecaSAndrey Smirnov * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem 729f1f50ecaSAndrey Smirnov * 730b378c779SSrinivas Kandagatla * @dev: Device that uses the nvmem device. 731f1f50ecaSAndrey Smirnov * @config: nvmem device configuration with which nvmem device is created. 732f1f50ecaSAndrey Smirnov * 733f1f50ecaSAndrey Smirnov * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device 734f1f50ecaSAndrey Smirnov * on success. 735f1f50ecaSAndrey Smirnov */ 736f1f50ecaSAndrey Smirnov struct nvmem_device *devm_nvmem_register(struct device *dev, 737f1f50ecaSAndrey Smirnov const struct nvmem_config *config) 738f1f50ecaSAndrey Smirnov { 739f1f50ecaSAndrey Smirnov struct nvmem_device **ptr, *nvmem; 740f1f50ecaSAndrey Smirnov 741f1f50ecaSAndrey Smirnov ptr = devres_alloc(devm_nvmem_release, sizeof(*ptr), GFP_KERNEL); 742f1f50ecaSAndrey Smirnov if (!ptr) 743f1f50ecaSAndrey Smirnov return ERR_PTR(-ENOMEM); 744f1f50ecaSAndrey Smirnov 745f1f50ecaSAndrey Smirnov nvmem = nvmem_register(config); 746f1f50ecaSAndrey Smirnov 747f1f50ecaSAndrey Smirnov if (!IS_ERR(nvmem)) { 748f1f50ecaSAndrey Smirnov *ptr = nvmem; 749f1f50ecaSAndrey Smirnov devres_add(dev, ptr); 750f1f50ecaSAndrey Smirnov } else { 751f1f50ecaSAndrey Smirnov devres_free(ptr); 752f1f50ecaSAndrey Smirnov } 753f1f50ecaSAndrey Smirnov 754f1f50ecaSAndrey Smirnov return nvmem; 755f1f50ecaSAndrey Smirnov } 756f1f50ecaSAndrey Smirnov EXPORT_SYMBOL_GPL(devm_nvmem_register); 757f1f50ecaSAndrey Smirnov 758f1f50ecaSAndrey Smirnov static int devm_nvmem_match(struct device *dev, void *res, void *data) 759f1f50ecaSAndrey Smirnov { 760f1f50ecaSAndrey Smirnov struct nvmem_device **r = res; 761f1f50ecaSAndrey Smirnov 762f1f50ecaSAndrey Smirnov return *r == data; 763f1f50ecaSAndrey Smirnov } 764f1f50ecaSAndrey Smirnov 765f1f50ecaSAndrey Smirnov /** 766f1f50ecaSAndrey Smirnov * devm_nvmem_unregister() - Unregister previously registered managed nvmem 767f1f50ecaSAndrey Smirnov * device. 768f1f50ecaSAndrey Smirnov * 769b378c779SSrinivas Kandagatla * @dev: Device that uses the nvmem device. 770f1f50ecaSAndrey Smirnov * @nvmem: Pointer to previously registered nvmem device. 771f1f50ecaSAndrey Smirnov * 772f1f50ecaSAndrey Smirnov * Return: Will be an negative on error or a zero on success. 773f1f50ecaSAndrey Smirnov */ 774f1f50ecaSAndrey Smirnov int devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem) 775f1f50ecaSAndrey Smirnov { 776f1f50ecaSAndrey Smirnov return devres_release(dev, devm_nvmem_release, devm_nvmem_match, nvmem); 777f1f50ecaSAndrey Smirnov } 778f1f50ecaSAndrey Smirnov EXPORT_SYMBOL(devm_nvmem_unregister); 779f1f50ecaSAndrey Smirnov 78069aba794SSrinivas Kandagatla static struct nvmem_device *__nvmem_device_get(struct device_node *np, 781506157beSBartosz Golaszewski const char *nvmem_name) 78269aba794SSrinivas Kandagatla { 78369aba794SSrinivas Kandagatla struct nvmem_device *nvmem = NULL; 78469aba794SSrinivas Kandagatla 785c7235ee3SBartosz Golaszewski mutex_lock(&nvmem_mutex); 786506157beSBartosz Golaszewski nvmem = np ? of_nvmem_find(np) : nvmem_find(nvmem_name); 78769aba794SSrinivas Kandagatla mutex_unlock(&nvmem_mutex); 788c7235ee3SBartosz Golaszewski if (!nvmem) 789c7235ee3SBartosz Golaszewski return ERR_PTR(-EPROBE_DEFER); 79069aba794SSrinivas Kandagatla 79169aba794SSrinivas Kandagatla if (!try_module_get(nvmem->owner)) { 79269aba794SSrinivas Kandagatla dev_err(&nvmem->dev, 79369aba794SSrinivas Kandagatla "could not increase module refcount for cell %s\n", 7945db652c9SBartosz Golaszewski nvmem_dev_name(nvmem)); 79569aba794SSrinivas Kandagatla 79669aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 79769aba794SSrinivas Kandagatla } 79869aba794SSrinivas Kandagatla 799c1de7f43SBartosz Golaszewski kref_get(&nvmem->refcnt); 800c1de7f43SBartosz Golaszewski 80169aba794SSrinivas Kandagatla return nvmem; 80269aba794SSrinivas Kandagatla } 80369aba794SSrinivas Kandagatla 80469aba794SSrinivas Kandagatla static void __nvmem_device_put(struct nvmem_device *nvmem) 80569aba794SSrinivas Kandagatla { 80669aba794SSrinivas Kandagatla module_put(nvmem->owner); 807c1de7f43SBartosz Golaszewski kref_put(&nvmem->refcnt, nvmem_device_release); 80869aba794SSrinivas Kandagatla } 80969aba794SSrinivas Kandagatla 810e701c67cSMasahiro Yamada #if IS_ENABLED(CONFIG_OF) 811e2a5402eSSrinivas Kandagatla /** 812e2a5402eSSrinivas Kandagatla * of_nvmem_device_get() - Get nvmem device from a given id 813e2a5402eSSrinivas Kandagatla * 81429143268SVivek Gautam * @np: Device tree node that uses the nvmem device. 815e2a5402eSSrinivas Kandagatla * @id: nvmem name from nvmem-names property. 816e2a5402eSSrinivas Kandagatla * 817e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device 818e2a5402eSSrinivas Kandagatla * on success. 819e2a5402eSSrinivas Kandagatla */ 820e2a5402eSSrinivas Kandagatla struct nvmem_device *of_nvmem_device_get(struct device_node *np, const char *id) 821e2a5402eSSrinivas Kandagatla { 822e2a5402eSSrinivas Kandagatla 823e2a5402eSSrinivas Kandagatla struct device_node *nvmem_np; 824e2a5402eSSrinivas Kandagatla int index; 825e2a5402eSSrinivas Kandagatla 826e2a5402eSSrinivas Kandagatla index = of_property_match_string(np, "nvmem-names", id); 827e2a5402eSSrinivas Kandagatla 828e2a5402eSSrinivas Kandagatla nvmem_np = of_parse_phandle(np, "nvmem", index); 829e2a5402eSSrinivas Kandagatla if (!nvmem_np) 830e2a5402eSSrinivas Kandagatla return ERR_PTR(-EINVAL); 831e2a5402eSSrinivas Kandagatla 832506157beSBartosz Golaszewski return __nvmem_device_get(nvmem_np, NULL); 833e2a5402eSSrinivas Kandagatla } 834e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_nvmem_device_get); 835e2a5402eSSrinivas Kandagatla #endif 836e2a5402eSSrinivas Kandagatla 837e2a5402eSSrinivas Kandagatla /** 838e2a5402eSSrinivas Kandagatla * nvmem_device_get() - Get nvmem device from a given id 839e2a5402eSSrinivas Kandagatla * 84029143268SVivek Gautam * @dev: Device that uses the nvmem device. 84129143268SVivek Gautam * @dev_name: name of the requested nvmem device. 842e2a5402eSSrinivas Kandagatla * 843e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device 844e2a5402eSSrinivas Kandagatla * on success. 845e2a5402eSSrinivas Kandagatla */ 846e2a5402eSSrinivas Kandagatla struct nvmem_device *nvmem_device_get(struct device *dev, const char *dev_name) 847e2a5402eSSrinivas Kandagatla { 848e2a5402eSSrinivas Kandagatla if (dev->of_node) { /* try dt first */ 849e2a5402eSSrinivas Kandagatla struct nvmem_device *nvmem; 850e2a5402eSSrinivas Kandagatla 851e2a5402eSSrinivas Kandagatla nvmem = of_nvmem_device_get(dev->of_node, dev_name); 852e2a5402eSSrinivas Kandagatla 853e2a5402eSSrinivas Kandagatla if (!IS_ERR(nvmem) || PTR_ERR(nvmem) == -EPROBE_DEFER) 854e2a5402eSSrinivas Kandagatla return nvmem; 855e2a5402eSSrinivas Kandagatla 856e2a5402eSSrinivas Kandagatla } 857e2a5402eSSrinivas Kandagatla 858e2a5402eSSrinivas Kandagatla return nvmem_find(dev_name); 859e2a5402eSSrinivas Kandagatla } 860e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_get); 861e2a5402eSSrinivas Kandagatla 862e2a5402eSSrinivas Kandagatla static int devm_nvmem_device_match(struct device *dev, void *res, void *data) 863e2a5402eSSrinivas Kandagatla { 864e2a5402eSSrinivas Kandagatla struct nvmem_device **nvmem = res; 865e2a5402eSSrinivas Kandagatla 866e2a5402eSSrinivas Kandagatla if (WARN_ON(!nvmem || !*nvmem)) 867e2a5402eSSrinivas Kandagatla return 0; 868e2a5402eSSrinivas Kandagatla 869e2a5402eSSrinivas Kandagatla return *nvmem == data; 870e2a5402eSSrinivas Kandagatla } 871e2a5402eSSrinivas Kandagatla 872e2a5402eSSrinivas Kandagatla static void devm_nvmem_device_release(struct device *dev, void *res) 873e2a5402eSSrinivas Kandagatla { 874e2a5402eSSrinivas Kandagatla nvmem_device_put(*(struct nvmem_device **)res); 875e2a5402eSSrinivas Kandagatla } 876e2a5402eSSrinivas Kandagatla 877e2a5402eSSrinivas Kandagatla /** 878e2a5402eSSrinivas Kandagatla * devm_nvmem_device_put() - put alredy got nvmem device 879e2a5402eSSrinivas Kandagatla * 88029143268SVivek Gautam * @dev: Device that uses the nvmem device. 881e2a5402eSSrinivas Kandagatla * @nvmem: pointer to nvmem device allocated by devm_nvmem_cell_get(), 882e2a5402eSSrinivas Kandagatla * that needs to be released. 883e2a5402eSSrinivas Kandagatla */ 884e2a5402eSSrinivas Kandagatla void devm_nvmem_device_put(struct device *dev, struct nvmem_device *nvmem) 885e2a5402eSSrinivas Kandagatla { 886e2a5402eSSrinivas Kandagatla int ret; 887e2a5402eSSrinivas Kandagatla 888e2a5402eSSrinivas Kandagatla ret = devres_release(dev, devm_nvmem_device_release, 889e2a5402eSSrinivas Kandagatla devm_nvmem_device_match, nvmem); 890e2a5402eSSrinivas Kandagatla 891e2a5402eSSrinivas Kandagatla WARN_ON(ret); 892e2a5402eSSrinivas Kandagatla } 893e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_device_put); 894e2a5402eSSrinivas Kandagatla 895e2a5402eSSrinivas Kandagatla /** 896e2a5402eSSrinivas Kandagatla * nvmem_device_put() - put alredy got nvmem device 897e2a5402eSSrinivas Kandagatla * 898e2a5402eSSrinivas Kandagatla * @nvmem: pointer to nvmem device that needs to be released. 899e2a5402eSSrinivas Kandagatla */ 900e2a5402eSSrinivas Kandagatla void nvmem_device_put(struct nvmem_device *nvmem) 901e2a5402eSSrinivas Kandagatla { 902e2a5402eSSrinivas Kandagatla __nvmem_device_put(nvmem); 903e2a5402eSSrinivas Kandagatla } 904e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_put); 905e2a5402eSSrinivas Kandagatla 906e2a5402eSSrinivas Kandagatla /** 907e2a5402eSSrinivas Kandagatla * devm_nvmem_device_get() - Get nvmem cell of device form a given id 908e2a5402eSSrinivas Kandagatla * 90929143268SVivek Gautam * @dev: Device that requests the nvmem device. 91029143268SVivek Gautam * @id: name id for the requested nvmem device. 911e2a5402eSSrinivas Kandagatla * 912e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_cell 913e2a5402eSSrinivas Kandagatla * on success. The nvmem_cell will be freed by the automatically once the 914e2a5402eSSrinivas Kandagatla * device is freed. 915e2a5402eSSrinivas Kandagatla */ 916e2a5402eSSrinivas Kandagatla struct nvmem_device *devm_nvmem_device_get(struct device *dev, const char *id) 917e2a5402eSSrinivas Kandagatla { 918e2a5402eSSrinivas Kandagatla struct nvmem_device **ptr, *nvmem; 919e2a5402eSSrinivas Kandagatla 920e2a5402eSSrinivas Kandagatla ptr = devres_alloc(devm_nvmem_device_release, sizeof(*ptr), GFP_KERNEL); 921e2a5402eSSrinivas Kandagatla if (!ptr) 922e2a5402eSSrinivas Kandagatla return ERR_PTR(-ENOMEM); 923e2a5402eSSrinivas Kandagatla 924e2a5402eSSrinivas Kandagatla nvmem = nvmem_device_get(dev, id); 925e2a5402eSSrinivas Kandagatla if (!IS_ERR(nvmem)) { 926e2a5402eSSrinivas Kandagatla *ptr = nvmem; 927e2a5402eSSrinivas Kandagatla devres_add(dev, ptr); 928e2a5402eSSrinivas Kandagatla } else { 929e2a5402eSSrinivas Kandagatla devres_free(ptr); 930e2a5402eSSrinivas Kandagatla } 931e2a5402eSSrinivas Kandagatla 932e2a5402eSSrinivas Kandagatla return nvmem; 933e2a5402eSSrinivas Kandagatla } 934e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_device_get); 935e2a5402eSSrinivas Kandagatla 936506157beSBartosz Golaszewski static struct nvmem_cell * 937506157beSBartosz Golaszewski nvmem_cell_get_from_lookup(struct device *dev, const char *con_id) 93869aba794SSrinivas Kandagatla { 939506157beSBartosz Golaszewski struct nvmem_cell *cell = ERR_PTR(-ENOENT); 940506157beSBartosz Golaszewski struct nvmem_cell_lookup *lookup; 94169aba794SSrinivas Kandagatla struct nvmem_device *nvmem; 942506157beSBartosz Golaszewski const char *dev_id; 94369aba794SSrinivas Kandagatla 944506157beSBartosz Golaszewski if (!dev) 945506157beSBartosz Golaszewski return ERR_PTR(-EINVAL); 94669aba794SSrinivas Kandagatla 947506157beSBartosz Golaszewski dev_id = dev_name(dev); 948506157beSBartosz Golaszewski 949506157beSBartosz Golaszewski mutex_lock(&nvmem_lookup_mutex); 950506157beSBartosz Golaszewski 951506157beSBartosz Golaszewski list_for_each_entry(lookup, &nvmem_lookup_list, node) { 952506157beSBartosz Golaszewski if ((strcmp(lookup->dev_id, dev_id) == 0) && 953506157beSBartosz Golaszewski (strcmp(lookup->con_id, con_id) == 0)) { 954506157beSBartosz Golaszewski /* This is the right entry. */ 955506157beSBartosz Golaszewski nvmem = __nvmem_device_get(NULL, lookup->nvmem_name); 956506157beSBartosz Golaszewski if (!nvmem) { 957506157beSBartosz Golaszewski /* Provider may not be registered yet. */ 958506157beSBartosz Golaszewski cell = ERR_PTR(-EPROBE_DEFER); 959506157beSBartosz Golaszewski goto out; 960506157beSBartosz Golaszewski } 961506157beSBartosz Golaszewski 962506157beSBartosz Golaszewski cell = nvmem_find_cell_by_name(nvmem, 963506157beSBartosz Golaszewski lookup->cell_name); 964506157beSBartosz Golaszewski if (!cell) { 965506157beSBartosz Golaszewski __nvmem_device_put(nvmem); 966506157beSBartosz Golaszewski goto out; 967506157beSBartosz Golaszewski } 968506157beSBartosz Golaszewski } 969506157beSBartosz Golaszewski } 970506157beSBartosz Golaszewski 971506157beSBartosz Golaszewski out: 972506157beSBartosz Golaszewski mutex_unlock(&nvmem_lookup_mutex); 97369aba794SSrinivas Kandagatla return cell; 97469aba794SSrinivas Kandagatla } 97569aba794SSrinivas Kandagatla 976e701c67cSMasahiro Yamada #if IS_ENABLED(CONFIG_OF) 97769aba794SSrinivas Kandagatla /** 97869aba794SSrinivas Kandagatla * of_nvmem_cell_get() - Get a nvmem cell from given device node and cell id 97969aba794SSrinivas Kandagatla * 98029143268SVivek Gautam * @np: Device tree node that uses the nvmem cell. 981165589f0SBartosz Golaszewski * @id: nvmem cell name from nvmem-cell-names property, or NULL 982fd0c478cSVivek Gautam * for the cell at index 0 (the lone cell with no accompanying 983fd0c478cSVivek Gautam * nvmem-cell-names property). 98469aba794SSrinivas Kandagatla * 98569aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 98669aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 98769aba794SSrinivas Kandagatla * nvmem_cell_put(). 98869aba794SSrinivas Kandagatla */ 989165589f0SBartosz Golaszewski struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *id) 99069aba794SSrinivas Kandagatla { 99169aba794SSrinivas Kandagatla struct device_node *cell_np, *nvmem_np; 99269aba794SSrinivas Kandagatla struct nvmem_device *nvmem; 993e888d445SBartosz Golaszewski struct nvmem_cell *cell; 994fd0c478cSVivek Gautam int index = 0; 99569aba794SSrinivas Kandagatla 996fd0c478cSVivek Gautam /* if cell name exists, find index to the name */ 997165589f0SBartosz Golaszewski if (id) 998165589f0SBartosz Golaszewski index = of_property_match_string(np, "nvmem-cell-names", id); 99969aba794SSrinivas Kandagatla 100069aba794SSrinivas Kandagatla cell_np = of_parse_phandle(np, "nvmem-cells", index); 100169aba794SSrinivas Kandagatla if (!cell_np) 100269aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 100369aba794SSrinivas Kandagatla 100469aba794SSrinivas Kandagatla nvmem_np = of_get_next_parent(cell_np); 100569aba794SSrinivas Kandagatla if (!nvmem_np) 100669aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 100769aba794SSrinivas Kandagatla 1008506157beSBartosz Golaszewski nvmem = __nvmem_device_get(nvmem_np, NULL); 1009aad8d097SMasahiro Yamada of_node_put(nvmem_np); 101069aba794SSrinivas Kandagatla if (IS_ERR(nvmem)) 101169aba794SSrinivas Kandagatla return ERR_CAST(nvmem); 101269aba794SSrinivas Kandagatla 1013e888d445SBartosz Golaszewski cell = nvmem_find_cell_by_index(nvmem, index); 101469aba794SSrinivas Kandagatla if (!cell) { 1015e888d445SBartosz Golaszewski __nvmem_device_put(nvmem); 1016e888d445SBartosz Golaszewski return ERR_PTR(-ENOENT); 101769aba794SSrinivas Kandagatla } 101869aba794SSrinivas Kandagatla 101969aba794SSrinivas Kandagatla return cell; 102069aba794SSrinivas Kandagatla } 102169aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_nvmem_cell_get); 102269aba794SSrinivas Kandagatla #endif 102369aba794SSrinivas Kandagatla 102469aba794SSrinivas Kandagatla /** 102569aba794SSrinivas Kandagatla * nvmem_cell_get() - Get nvmem cell of device form a given cell name 102669aba794SSrinivas Kandagatla * 102729143268SVivek Gautam * @dev: Device that requests the nvmem cell. 1028165589f0SBartosz Golaszewski * @id: nvmem cell name to get (this corresponds with the name from the 1029165589f0SBartosz Golaszewski * nvmem-cell-names property for DT systems and with the con_id from 1030165589f0SBartosz Golaszewski * the lookup entry for non-DT systems). 103169aba794SSrinivas Kandagatla * 103269aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 103369aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 103469aba794SSrinivas Kandagatla * nvmem_cell_put(). 103569aba794SSrinivas Kandagatla */ 1036165589f0SBartosz Golaszewski struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *id) 103769aba794SSrinivas Kandagatla { 103869aba794SSrinivas Kandagatla struct nvmem_cell *cell; 103969aba794SSrinivas Kandagatla 104069aba794SSrinivas Kandagatla if (dev->of_node) { /* try dt first */ 1041165589f0SBartosz Golaszewski cell = of_nvmem_cell_get(dev->of_node, id); 104269aba794SSrinivas Kandagatla if (!IS_ERR(cell) || PTR_ERR(cell) == -EPROBE_DEFER) 104369aba794SSrinivas Kandagatla return cell; 104469aba794SSrinivas Kandagatla } 104569aba794SSrinivas Kandagatla 1046165589f0SBartosz Golaszewski /* NULL cell id only allowed for device tree; invalid otherwise */ 1047165589f0SBartosz Golaszewski if (!id) 104887ed1405SDouglas Anderson return ERR_PTR(-EINVAL); 104987ed1405SDouglas Anderson 1050165589f0SBartosz Golaszewski return nvmem_cell_get_from_lookup(dev, id); 105169aba794SSrinivas Kandagatla } 105269aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_get); 105369aba794SSrinivas Kandagatla 105469aba794SSrinivas Kandagatla static void devm_nvmem_cell_release(struct device *dev, void *res) 105569aba794SSrinivas Kandagatla { 105669aba794SSrinivas Kandagatla nvmem_cell_put(*(struct nvmem_cell **)res); 105769aba794SSrinivas Kandagatla } 105869aba794SSrinivas Kandagatla 105969aba794SSrinivas Kandagatla /** 106069aba794SSrinivas Kandagatla * devm_nvmem_cell_get() - Get nvmem cell of device form a given id 106169aba794SSrinivas Kandagatla * 106229143268SVivek Gautam * @dev: Device that requests the nvmem cell. 106329143268SVivek Gautam * @id: nvmem cell name id to get. 106469aba794SSrinivas Kandagatla * 106569aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 106669aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 106769aba794SSrinivas Kandagatla * automatically once the device is freed. 106869aba794SSrinivas Kandagatla */ 106969aba794SSrinivas Kandagatla struct nvmem_cell *devm_nvmem_cell_get(struct device *dev, const char *id) 107069aba794SSrinivas Kandagatla { 107169aba794SSrinivas Kandagatla struct nvmem_cell **ptr, *cell; 107269aba794SSrinivas Kandagatla 107369aba794SSrinivas Kandagatla ptr = devres_alloc(devm_nvmem_cell_release, sizeof(*ptr), GFP_KERNEL); 107469aba794SSrinivas Kandagatla if (!ptr) 107569aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 107669aba794SSrinivas Kandagatla 107769aba794SSrinivas Kandagatla cell = nvmem_cell_get(dev, id); 107869aba794SSrinivas Kandagatla if (!IS_ERR(cell)) { 107969aba794SSrinivas Kandagatla *ptr = cell; 108069aba794SSrinivas Kandagatla devres_add(dev, ptr); 108169aba794SSrinivas Kandagatla } else { 108269aba794SSrinivas Kandagatla devres_free(ptr); 108369aba794SSrinivas Kandagatla } 108469aba794SSrinivas Kandagatla 108569aba794SSrinivas Kandagatla return cell; 108669aba794SSrinivas Kandagatla } 108769aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_cell_get); 108869aba794SSrinivas Kandagatla 108969aba794SSrinivas Kandagatla static int devm_nvmem_cell_match(struct device *dev, void *res, void *data) 109069aba794SSrinivas Kandagatla { 109169aba794SSrinivas Kandagatla struct nvmem_cell **c = res; 109269aba794SSrinivas Kandagatla 109369aba794SSrinivas Kandagatla if (WARN_ON(!c || !*c)) 109469aba794SSrinivas Kandagatla return 0; 109569aba794SSrinivas Kandagatla 109669aba794SSrinivas Kandagatla return *c == data; 109769aba794SSrinivas Kandagatla } 109869aba794SSrinivas Kandagatla 109969aba794SSrinivas Kandagatla /** 110069aba794SSrinivas Kandagatla * devm_nvmem_cell_put() - Release previously allocated nvmem cell 110169aba794SSrinivas Kandagatla * from devm_nvmem_cell_get. 110269aba794SSrinivas Kandagatla * 110329143268SVivek Gautam * @dev: Device that requests the nvmem cell. 110429143268SVivek Gautam * @cell: Previously allocated nvmem cell by devm_nvmem_cell_get(). 110569aba794SSrinivas Kandagatla */ 110669aba794SSrinivas Kandagatla void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell) 110769aba794SSrinivas Kandagatla { 110869aba794SSrinivas Kandagatla int ret; 110969aba794SSrinivas Kandagatla 111069aba794SSrinivas Kandagatla ret = devres_release(dev, devm_nvmem_cell_release, 111169aba794SSrinivas Kandagatla devm_nvmem_cell_match, cell); 111269aba794SSrinivas Kandagatla 111369aba794SSrinivas Kandagatla WARN_ON(ret); 111469aba794SSrinivas Kandagatla } 111569aba794SSrinivas Kandagatla EXPORT_SYMBOL(devm_nvmem_cell_put); 111669aba794SSrinivas Kandagatla 111769aba794SSrinivas Kandagatla /** 111869aba794SSrinivas Kandagatla * nvmem_cell_put() - Release previously allocated nvmem cell. 111969aba794SSrinivas Kandagatla * 112029143268SVivek Gautam * @cell: Previously allocated nvmem cell by nvmem_cell_get(). 112169aba794SSrinivas Kandagatla */ 112269aba794SSrinivas Kandagatla void nvmem_cell_put(struct nvmem_cell *cell) 112369aba794SSrinivas Kandagatla { 112469aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 112569aba794SSrinivas Kandagatla 112669aba794SSrinivas Kandagatla __nvmem_device_put(nvmem); 112769aba794SSrinivas Kandagatla } 112869aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_put); 112969aba794SSrinivas Kandagatla 1130f7c04f16SMasahiro Yamada static void nvmem_shift_read_buffer_in_place(struct nvmem_cell *cell, void *buf) 113169aba794SSrinivas Kandagatla { 113269aba794SSrinivas Kandagatla u8 *p, *b; 113369aba794SSrinivas Kandagatla int i, bit_offset = cell->bit_offset; 113469aba794SSrinivas Kandagatla 113569aba794SSrinivas Kandagatla p = b = buf; 113669aba794SSrinivas Kandagatla if (bit_offset) { 113769aba794SSrinivas Kandagatla /* First shift */ 113869aba794SSrinivas Kandagatla *b++ >>= bit_offset; 113969aba794SSrinivas Kandagatla 114069aba794SSrinivas Kandagatla /* setup rest of the bytes if any */ 114169aba794SSrinivas Kandagatla for (i = 1; i < cell->bytes; i++) { 114269aba794SSrinivas Kandagatla /* Get bits from next byte and shift them towards msb */ 114369aba794SSrinivas Kandagatla *p |= *b << (BITS_PER_BYTE - bit_offset); 114469aba794SSrinivas Kandagatla 114569aba794SSrinivas Kandagatla p = b; 114669aba794SSrinivas Kandagatla *b++ >>= bit_offset; 114769aba794SSrinivas Kandagatla } 114869aba794SSrinivas Kandagatla 114969aba794SSrinivas Kandagatla /* result fits in less bytes */ 115069aba794SSrinivas Kandagatla if (cell->bytes != DIV_ROUND_UP(cell->nbits, BITS_PER_BYTE)) 115169aba794SSrinivas Kandagatla *p-- = 0; 115269aba794SSrinivas Kandagatla } 115369aba794SSrinivas Kandagatla /* clear msb bits if any leftover in the last byte */ 115469aba794SSrinivas Kandagatla *p &= GENMASK((cell->nbits%BITS_PER_BYTE) - 1, 0); 115569aba794SSrinivas Kandagatla } 115669aba794SSrinivas Kandagatla 115769aba794SSrinivas Kandagatla static int __nvmem_cell_read(struct nvmem_device *nvmem, 115869aba794SSrinivas Kandagatla struct nvmem_cell *cell, 115969aba794SSrinivas Kandagatla void *buf, size_t *len) 116069aba794SSrinivas Kandagatla { 116169aba794SSrinivas Kandagatla int rc; 116269aba794SSrinivas Kandagatla 1163795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, cell->offset, buf, cell->bytes); 116469aba794SSrinivas Kandagatla 1165287980e4SArnd Bergmann if (rc) 116669aba794SSrinivas Kandagatla return rc; 116769aba794SSrinivas Kandagatla 116869aba794SSrinivas Kandagatla /* shift bits in-place */ 1169cbf854abSAxel Lin if (cell->bit_offset || cell->nbits) 117069aba794SSrinivas Kandagatla nvmem_shift_read_buffer_in_place(cell, buf); 117169aba794SSrinivas Kandagatla 11723b4a6877SVivek Gautam if (len) 117369aba794SSrinivas Kandagatla *len = cell->bytes; 117469aba794SSrinivas Kandagatla 117569aba794SSrinivas Kandagatla return 0; 117669aba794SSrinivas Kandagatla } 117769aba794SSrinivas Kandagatla 117869aba794SSrinivas Kandagatla /** 117969aba794SSrinivas Kandagatla * nvmem_cell_read() - Read a given nvmem cell 118069aba794SSrinivas Kandagatla * 118169aba794SSrinivas Kandagatla * @cell: nvmem cell to be read. 11823b4a6877SVivek Gautam * @len: pointer to length of cell which will be populated on successful read; 11833b4a6877SVivek Gautam * can be NULL. 118469aba794SSrinivas Kandagatla * 1185b577fafcSBrian Norris * Return: ERR_PTR() on error or a valid pointer to a buffer on success. The 1186b577fafcSBrian Norris * buffer should be freed by the consumer with a kfree(). 118769aba794SSrinivas Kandagatla */ 118869aba794SSrinivas Kandagatla void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len) 118969aba794SSrinivas Kandagatla { 119069aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 119169aba794SSrinivas Kandagatla u8 *buf; 119269aba794SSrinivas Kandagatla int rc; 119369aba794SSrinivas Kandagatla 1194795ddd18SSrinivas Kandagatla if (!nvmem) 119569aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 119669aba794SSrinivas Kandagatla 119769aba794SSrinivas Kandagatla buf = kzalloc(cell->bytes, GFP_KERNEL); 119869aba794SSrinivas Kandagatla if (!buf) 119969aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 120069aba794SSrinivas Kandagatla 120169aba794SSrinivas Kandagatla rc = __nvmem_cell_read(nvmem, cell, buf, len); 1202287980e4SArnd Bergmann if (rc) { 120369aba794SSrinivas Kandagatla kfree(buf); 120469aba794SSrinivas Kandagatla return ERR_PTR(rc); 120569aba794SSrinivas Kandagatla } 120669aba794SSrinivas Kandagatla 120769aba794SSrinivas Kandagatla return buf; 120869aba794SSrinivas Kandagatla } 120969aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_read); 121069aba794SSrinivas Kandagatla 1211f7c04f16SMasahiro Yamada static void *nvmem_cell_prepare_write_buffer(struct nvmem_cell *cell, 121269aba794SSrinivas Kandagatla u8 *_buf, int len) 121369aba794SSrinivas Kandagatla { 121469aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 121569aba794SSrinivas Kandagatla int i, rc, nbits, bit_offset = cell->bit_offset; 121669aba794SSrinivas Kandagatla u8 v, *p, *buf, *b, pbyte, pbits; 121769aba794SSrinivas Kandagatla 121869aba794SSrinivas Kandagatla nbits = cell->nbits; 121969aba794SSrinivas Kandagatla buf = kzalloc(cell->bytes, GFP_KERNEL); 122069aba794SSrinivas Kandagatla if (!buf) 122169aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 122269aba794SSrinivas Kandagatla 122369aba794SSrinivas Kandagatla memcpy(buf, _buf, len); 122469aba794SSrinivas Kandagatla p = b = buf; 122569aba794SSrinivas Kandagatla 122669aba794SSrinivas Kandagatla if (bit_offset) { 122769aba794SSrinivas Kandagatla pbyte = *b; 122869aba794SSrinivas Kandagatla *b <<= bit_offset; 122969aba794SSrinivas Kandagatla 123069aba794SSrinivas Kandagatla /* setup the first byte with lsb bits from nvmem */ 1231795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, cell->offset, &v, 1); 123250808bfcSMathieu Malaterre if (rc) 123350808bfcSMathieu Malaterre goto err; 123469aba794SSrinivas Kandagatla *b++ |= GENMASK(bit_offset - 1, 0) & v; 123569aba794SSrinivas Kandagatla 123669aba794SSrinivas Kandagatla /* setup rest of the byte if any */ 123769aba794SSrinivas Kandagatla for (i = 1; i < cell->bytes; i++) { 123869aba794SSrinivas Kandagatla /* Get last byte bits and shift them towards lsb */ 123969aba794SSrinivas Kandagatla pbits = pbyte >> (BITS_PER_BYTE - 1 - bit_offset); 124069aba794SSrinivas Kandagatla pbyte = *b; 124169aba794SSrinivas Kandagatla p = b; 124269aba794SSrinivas Kandagatla *b <<= bit_offset; 124369aba794SSrinivas Kandagatla *b++ |= pbits; 124469aba794SSrinivas Kandagatla } 124569aba794SSrinivas Kandagatla } 124669aba794SSrinivas Kandagatla 124769aba794SSrinivas Kandagatla /* if it's not end on byte boundary */ 124869aba794SSrinivas Kandagatla if ((nbits + bit_offset) % BITS_PER_BYTE) { 124969aba794SSrinivas Kandagatla /* setup the last byte with msb bits from nvmem */ 1250795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, 125169aba794SSrinivas Kandagatla cell->offset + cell->bytes - 1, &v, 1); 125250808bfcSMathieu Malaterre if (rc) 125350808bfcSMathieu Malaterre goto err; 125469aba794SSrinivas Kandagatla *p |= GENMASK(7, (nbits + bit_offset) % BITS_PER_BYTE) & v; 125569aba794SSrinivas Kandagatla 125669aba794SSrinivas Kandagatla } 125769aba794SSrinivas Kandagatla 125869aba794SSrinivas Kandagatla return buf; 125950808bfcSMathieu Malaterre err: 126050808bfcSMathieu Malaterre kfree(buf); 126150808bfcSMathieu Malaterre return ERR_PTR(rc); 126269aba794SSrinivas Kandagatla } 126369aba794SSrinivas Kandagatla 126469aba794SSrinivas Kandagatla /** 126569aba794SSrinivas Kandagatla * nvmem_cell_write() - Write to a given nvmem cell 126669aba794SSrinivas Kandagatla * 126769aba794SSrinivas Kandagatla * @cell: nvmem cell to be written. 126869aba794SSrinivas Kandagatla * @buf: Buffer to be written. 126969aba794SSrinivas Kandagatla * @len: length of buffer to be written to nvmem cell. 127069aba794SSrinivas Kandagatla * 127169aba794SSrinivas Kandagatla * Return: length of bytes written or negative on failure. 127269aba794SSrinivas Kandagatla */ 127369aba794SSrinivas Kandagatla int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len) 127469aba794SSrinivas Kandagatla { 127569aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 127669aba794SSrinivas Kandagatla int rc; 127769aba794SSrinivas Kandagatla 1278795ddd18SSrinivas Kandagatla if (!nvmem || nvmem->read_only || 127969aba794SSrinivas Kandagatla (cell->bit_offset == 0 && len != cell->bytes)) 128069aba794SSrinivas Kandagatla return -EINVAL; 128169aba794SSrinivas Kandagatla 128269aba794SSrinivas Kandagatla if (cell->bit_offset || cell->nbits) { 128369aba794SSrinivas Kandagatla buf = nvmem_cell_prepare_write_buffer(cell, buf, len); 128469aba794SSrinivas Kandagatla if (IS_ERR(buf)) 128569aba794SSrinivas Kandagatla return PTR_ERR(buf); 128669aba794SSrinivas Kandagatla } 128769aba794SSrinivas Kandagatla 1288795ddd18SSrinivas Kandagatla rc = nvmem_reg_write(nvmem, cell->offset, buf, cell->bytes); 128969aba794SSrinivas Kandagatla 129069aba794SSrinivas Kandagatla /* free the tmp buffer */ 1291ace22170SAxel Lin if (cell->bit_offset || cell->nbits) 129269aba794SSrinivas Kandagatla kfree(buf); 129369aba794SSrinivas Kandagatla 1294287980e4SArnd Bergmann if (rc) 129569aba794SSrinivas Kandagatla return rc; 129669aba794SSrinivas Kandagatla 129769aba794SSrinivas Kandagatla return len; 129869aba794SSrinivas Kandagatla } 129969aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_write); 130069aba794SSrinivas Kandagatla 1301e2a5402eSSrinivas Kandagatla /** 1302d026d70aSLeonard Crestez * nvmem_cell_read_u32() - Read a cell value as an u32 1303d026d70aSLeonard Crestez * 1304d026d70aSLeonard Crestez * @dev: Device that requests the nvmem cell. 1305d026d70aSLeonard Crestez * @cell_id: Name of nvmem cell to read. 1306d026d70aSLeonard Crestez * @val: pointer to output value. 1307d026d70aSLeonard Crestez * 1308d026d70aSLeonard Crestez * Return: 0 on success or negative errno. 1309d026d70aSLeonard Crestez */ 1310d026d70aSLeonard Crestez int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val) 1311d026d70aSLeonard Crestez { 1312d026d70aSLeonard Crestez struct nvmem_cell *cell; 1313d026d70aSLeonard Crestez void *buf; 1314d026d70aSLeonard Crestez size_t len; 1315d026d70aSLeonard Crestez 1316d026d70aSLeonard Crestez cell = nvmem_cell_get(dev, cell_id); 1317d026d70aSLeonard Crestez if (IS_ERR(cell)) 1318d026d70aSLeonard Crestez return PTR_ERR(cell); 1319d026d70aSLeonard Crestez 1320d026d70aSLeonard Crestez buf = nvmem_cell_read(cell, &len); 1321d026d70aSLeonard Crestez if (IS_ERR(buf)) { 1322d026d70aSLeonard Crestez nvmem_cell_put(cell); 1323d026d70aSLeonard Crestez return PTR_ERR(buf); 1324d026d70aSLeonard Crestez } 1325d026d70aSLeonard Crestez if (len != sizeof(*val)) { 1326d026d70aSLeonard Crestez kfree(buf); 1327d026d70aSLeonard Crestez nvmem_cell_put(cell); 1328d026d70aSLeonard Crestez return -EINVAL; 1329d026d70aSLeonard Crestez } 1330d026d70aSLeonard Crestez memcpy(val, buf, sizeof(*val)); 1331d026d70aSLeonard Crestez 1332d026d70aSLeonard Crestez kfree(buf); 1333d026d70aSLeonard Crestez nvmem_cell_put(cell); 1334d026d70aSLeonard Crestez return 0; 1335d026d70aSLeonard Crestez } 1336d026d70aSLeonard Crestez EXPORT_SYMBOL_GPL(nvmem_cell_read_u32); 1337d026d70aSLeonard Crestez 1338d026d70aSLeonard Crestez /** 1339e2a5402eSSrinivas Kandagatla * nvmem_device_cell_read() - Read a given nvmem device and cell 1340e2a5402eSSrinivas Kandagatla * 1341e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to read from. 1342e2a5402eSSrinivas Kandagatla * @info: nvmem cell info to be read. 1343e2a5402eSSrinivas Kandagatla * @buf: buffer pointer which will be populated on successful read. 1344e2a5402eSSrinivas Kandagatla * 1345e2a5402eSSrinivas Kandagatla * Return: length of successful bytes read on success and negative 1346e2a5402eSSrinivas Kandagatla * error code on error. 1347e2a5402eSSrinivas Kandagatla */ 1348e2a5402eSSrinivas Kandagatla ssize_t nvmem_device_cell_read(struct nvmem_device *nvmem, 1349e2a5402eSSrinivas Kandagatla struct nvmem_cell_info *info, void *buf) 1350e2a5402eSSrinivas Kandagatla { 1351e2a5402eSSrinivas Kandagatla struct nvmem_cell cell; 1352e2a5402eSSrinivas Kandagatla int rc; 1353e2a5402eSSrinivas Kandagatla ssize_t len; 1354e2a5402eSSrinivas Kandagatla 1355795ddd18SSrinivas Kandagatla if (!nvmem) 1356e2a5402eSSrinivas Kandagatla return -EINVAL; 1357e2a5402eSSrinivas Kandagatla 1358e2a5402eSSrinivas Kandagatla rc = nvmem_cell_info_to_nvmem_cell(nvmem, info, &cell); 1359287980e4SArnd Bergmann if (rc) 1360e2a5402eSSrinivas Kandagatla return rc; 1361e2a5402eSSrinivas Kandagatla 1362e2a5402eSSrinivas Kandagatla rc = __nvmem_cell_read(nvmem, &cell, buf, &len); 1363287980e4SArnd Bergmann if (rc) 1364e2a5402eSSrinivas Kandagatla return rc; 1365e2a5402eSSrinivas Kandagatla 1366e2a5402eSSrinivas Kandagatla return len; 1367e2a5402eSSrinivas Kandagatla } 1368e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_cell_read); 1369e2a5402eSSrinivas Kandagatla 1370e2a5402eSSrinivas Kandagatla /** 1371e2a5402eSSrinivas Kandagatla * nvmem_device_cell_write() - Write cell to a given nvmem device 1372e2a5402eSSrinivas Kandagatla * 1373e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to be written to. 137429143268SVivek Gautam * @info: nvmem cell info to be written. 1375e2a5402eSSrinivas Kandagatla * @buf: buffer to be written to cell. 1376e2a5402eSSrinivas Kandagatla * 1377e2a5402eSSrinivas Kandagatla * Return: length of bytes written or negative error code on failure. 137848f63a2cSBartosz Golaszewski */ 1379e2a5402eSSrinivas Kandagatla int nvmem_device_cell_write(struct nvmem_device *nvmem, 1380e2a5402eSSrinivas Kandagatla struct nvmem_cell_info *info, void *buf) 1381e2a5402eSSrinivas Kandagatla { 1382e2a5402eSSrinivas Kandagatla struct nvmem_cell cell; 1383e2a5402eSSrinivas Kandagatla int rc; 1384e2a5402eSSrinivas Kandagatla 1385795ddd18SSrinivas Kandagatla if (!nvmem) 1386e2a5402eSSrinivas Kandagatla return -EINVAL; 1387e2a5402eSSrinivas Kandagatla 1388e2a5402eSSrinivas Kandagatla rc = nvmem_cell_info_to_nvmem_cell(nvmem, info, &cell); 1389287980e4SArnd Bergmann if (rc) 1390e2a5402eSSrinivas Kandagatla return rc; 1391e2a5402eSSrinivas Kandagatla 1392e2a5402eSSrinivas Kandagatla return nvmem_cell_write(&cell, buf, cell.bytes); 1393e2a5402eSSrinivas Kandagatla } 1394e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_cell_write); 1395e2a5402eSSrinivas Kandagatla 1396e2a5402eSSrinivas Kandagatla /** 1397e2a5402eSSrinivas Kandagatla * nvmem_device_read() - Read from a given nvmem device 1398e2a5402eSSrinivas Kandagatla * 1399e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to read from. 1400e2a5402eSSrinivas Kandagatla * @offset: offset in nvmem device. 1401e2a5402eSSrinivas Kandagatla * @bytes: number of bytes to read. 1402e2a5402eSSrinivas Kandagatla * @buf: buffer pointer which will be populated on successful read. 1403e2a5402eSSrinivas Kandagatla * 1404e2a5402eSSrinivas Kandagatla * Return: length of successful bytes read on success and negative 1405e2a5402eSSrinivas Kandagatla * error code on error. 1406e2a5402eSSrinivas Kandagatla */ 1407e2a5402eSSrinivas Kandagatla int nvmem_device_read(struct nvmem_device *nvmem, 1408e2a5402eSSrinivas Kandagatla unsigned int offset, 1409e2a5402eSSrinivas Kandagatla size_t bytes, void *buf) 1410e2a5402eSSrinivas Kandagatla { 1411e2a5402eSSrinivas Kandagatla int rc; 1412e2a5402eSSrinivas Kandagatla 1413795ddd18SSrinivas Kandagatla if (!nvmem) 1414e2a5402eSSrinivas Kandagatla return -EINVAL; 1415e2a5402eSSrinivas Kandagatla 1416795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, offset, buf, bytes); 1417e2a5402eSSrinivas Kandagatla 1418287980e4SArnd Bergmann if (rc) 1419e2a5402eSSrinivas Kandagatla return rc; 1420e2a5402eSSrinivas Kandagatla 1421e2a5402eSSrinivas Kandagatla return bytes; 1422e2a5402eSSrinivas Kandagatla } 1423e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_read); 1424e2a5402eSSrinivas Kandagatla 1425e2a5402eSSrinivas Kandagatla /** 1426e2a5402eSSrinivas Kandagatla * nvmem_device_write() - Write cell to a given nvmem device 1427e2a5402eSSrinivas Kandagatla * 1428e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to be written to. 1429e2a5402eSSrinivas Kandagatla * @offset: offset in nvmem device. 1430e2a5402eSSrinivas Kandagatla * @bytes: number of bytes to write. 1431e2a5402eSSrinivas Kandagatla * @buf: buffer to be written. 1432e2a5402eSSrinivas Kandagatla * 1433e2a5402eSSrinivas Kandagatla * Return: length of bytes written or negative error code on failure. 143448f63a2cSBartosz Golaszewski */ 1435e2a5402eSSrinivas Kandagatla int nvmem_device_write(struct nvmem_device *nvmem, 1436e2a5402eSSrinivas Kandagatla unsigned int offset, 1437e2a5402eSSrinivas Kandagatla size_t bytes, void *buf) 1438e2a5402eSSrinivas Kandagatla { 1439e2a5402eSSrinivas Kandagatla int rc; 1440e2a5402eSSrinivas Kandagatla 1441795ddd18SSrinivas Kandagatla if (!nvmem) 1442e2a5402eSSrinivas Kandagatla return -EINVAL; 1443e2a5402eSSrinivas Kandagatla 1444795ddd18SSrinivas Kandagatla rc = nvmem_reg_write(nvmem, offset, buf, bytes); 1445e2a5402eSSrinivas Kandagatla 1446287980e4SArnd Bergmann if (rc) 1447e2a5402eSSrinivas Kandagatla return rc; 1448e2a5402eSSrinivas Kandagatla 1449e2a5402eSSrinivas Kandagatla 1450e2a5402eSSrinivas Kandagatla return bytes; 1451e2a5402eSSrinivas Kandagatla } 1452e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_write); 1453e2a5402eSSrinivas Kandagatla 1454d7b9fd16SBartosz Golaszewski /** 1455b985f4cbSBartosz Golaszewski * nvmem_add_cell_table() - register a table of cell info entries 1456b985f4cbSBartosz Golaszewski * 1457b985f4cbSBartosz Golaszewski * @table: table of cell info entries 1458b985f4cbSBartosz Golaszewski */ 1459b985f4cbSBartosz Golaszewski void nvmem_add_cell_table(struct nvmem_cell_table *table) 1460b985f4cbSBartosz Golaszewski { 1461b985f4cbSBartosz Golaszewski mutex_lock(&nvmem_cell_mutex); 1462b985f4cbSBartosz Golaszewski list_add_tail(&table->node, &nvmem_cell_tables); 1463b985f4cbSBartosz Golaszewski mutex_unlock(&nvmem_cell_mutex); 1464b985f4cbSBartosz Golaszewski } 1465b985f4cbSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_add_cell_table); 1466b985f4cbSBartosz Golaszewski 1467b985f4cbSBartosz Golaszewski /** 1468b985f4cbSBartosz Golaszewski * nvmem_del_cell_table() - remove a previously registered cell info table 1469b985f4cbSBartosz Golaszewski * 1470b985f4cbSBartosz Golaszewski * @table: table of cell info entries 1471b985f4cbSBartosz Golaszewski */ 1472b985f4cbSBartosz Golaszewski void nvmem_del_cell_table(struct nvmem_cell_table *table) 1473b985f4cbSBartosz Golaszewski { 1474b985f4cbSBartosz Golaszewski mutex_lock(&nvmem_cell_mutex); 1475b985f4cbSBartosz Golaszewski list_del(&table->node); 1476b985f4cbSBartosz Golaszewski mutex_unlock(&nvmem_cell_mutex); 1477b985f4cbSBartosz Golaszewski } 1478b985f4cbSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_del_cell_table); 1479b985f4cbSBartosz Golaszewski 1480b985f4cbSBartosz Golaszewski /** 1481506157beSBartosz Golaszewski * nvmem_add_cell_lookups() - register a list of cell lookup entries 1482506157beSBartosz Golaszewski * 1483506157beSBartosz Golaszewski * @entries: array of cell lookup entries 1484506157beSBartosz Golaszewski * @nentries: number of cell lookup entries in the array 1485506157beSBartosz Golaszewski */ 1486506157beSBartosz Golaszewski void nvmem_add_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries) 1487506157beSBartosz Golaszewski { 1488506157beSBartosz Golaszewski int i; 1489506157beSBartosz Golaszewski 1490506157beSBartosz Golaszewski mutex_lock(&nvmem_lookup_mutex); 1491506157beSBartosz Golaszewski for (i = 0; i < nentries; i++) 1492506157beSBartosz Golaszewski list_add_tail(&entries[i].node, &nvmem_lookup_list); 1493506157beSBartosz Golaszewski mutex_unlock(&nvmem_lookup_mutex); 1494506157beSBartosz Golaszewski } 1495506157beSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_add_cell_lookups); 1496506157beSBartosz Golaszewski 1497506157beSBartosz Golaszewski /** 1498506157beSBartosz Golaszewski * nvmem_del_cell_lookups() - remove a list of previously added cell lookup 1499506157beSBartosz Golaszewski * entries 1500506157beSBartosz Golaszewski * 1501506157beSBartosz Golaszewski * @entries: array of cell lookup entries 1502506157beSBartosz Golaszewski * @nentries: number of cell lookup entries in the array 1503506157beSBartosz Golaszewski */ 1504506157beSBartosz Golaszewski void nvmem_del_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries) 1505506157beSBartosz Golaszewski { 1506506157beSBartosz Golaszewski int i; 1507506157beSBartosz Golaszewski 1508506157beSBartosz Golaszewski mutex_lock(&nvmem_lookup_mutex); 1509506157beSBartosz Golaszewski for (i = 0; i < nentries; i++) 1510506157beSBartosz Golaszewski list_del(&entries[i].node); 1511506157beSBartosz Golaszewski mutex_unlock(&nvmem_lookup_mutex); 1512506157beSBartosz Golaszewski } 1513506157beSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_del_cell_lookups); 1514506157beSBartosz Golaszewski 1515506157beSBartosz Golaszewski /** 1516d7b9fd16SBartosz Golaszewski * nvmem_dev_name() - Get the name of a given nvmem device. 1517d7b9fd16SBartosz Golaszewski * 1518d7b9fd16SBartosz Golaszewski * @nvmem: nvmem device. 1519d7b9fd16SBartosz Golaszewski * 1520d7b9fd16SBartosz Golaszewski * Return: name of the nvmem device. 1521d7b9fd16SBartosz Golaszewski */ 1522d7b9fd16SBartosz Golaszewski const char *nvmem_dev_name(struct nvmem_device *nvmem) 1523d7b9fd16SBartosz Golaszewski { 1524d7b9fd16SBartosz Golaszewski return dev_name(&nvmem->dev); 1525d7b9fd16SBartosz Golaszewski } 1526d7b9fd16SBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_dev_name); 1527d7b9fd16SBartosz Golaszewski 1528eace75cfSSrinivas Kandagatla static int __init nvmem_init(void) 1529eace75cfSSrinivas Kandagatla { 1530eace75cfSSrinivas Kandagatla return bus_register(&nvmem_bus_type); 1531eace75cfSSrinivas Kandagatla } 1532eace75cfSSrinivas Kandagatla 1533eace75cfSSrinivas Kandagatla static void __exit nvmem_exit(void) 1534eace75cfSSrinivas Kandagatla { 1535eace75cfSSrinivas Kandagatla bus_unregister(&nvmem_bus_type); 1536eace75cfSSrinivas Kandagatla } 1537eace75cfSSrinivas Kandagatla 1538eace75cfSSrinivas Kandagatla subsys_initcall(nvmem_init); 1539eace75cfSSrinivas Kandagatla module_exit(nvmem_exit); 1540eace75cfSSrinivas Kandagatla 1541eace75cfSSrinivas Kandagatla MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org"); 1542eace75cfSSrinivas Kandagatla MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com"); 1543eace75cfSSrinivas Kandagatla MODULE_DESCRIPTION("nvmem Driver Core"); 1544eace75cfSSrinivas Kandagatla MODULE_LICENSE("GPL v2"); 1545