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", 157eace75cfSSrinivas Kandagatla .mode = S_IWUSR | S_IRUGO, 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", 181eace75cfSSrinivas Kandagatla .mode = S_IRUGO, 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", 204811b0d65SAndrew Lunn .mode = S_IWUSR | S_IRUSR, 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", 228811b0d65SAndrew Lunn .mode = S_IRUSR, 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); 301eace75cfSSrinivas Kandagatla kfree(cell); 302eace75cfSSrinivas Kandagatla } 303eace75cfSSrinivas Kandagatla 304eace75cfSSrinivas Kandagatla static void nvmem_device_remove_all_cells(const struct nvmem_device *nvmem) 305eace75cfSSrinivas Kandagatla { 3061852183eSBartosz Golaszewski struct nvmem_cell *cell, *p; 307eace75cfSSrinivas Kandagatla 308c7235ee3SBartosz Golaszewski list_for_each_entry_safe(cell, p, &nvmem->cells, node) 309eace75cfSSrinivas Kandagatla nvmem_cell_drop(cell); 310eace75cfSSrinivas Kandagatla } 311eace75cfSSrinivas Kandagatla 312eace75cfSSrinivas Kandagatla static void nvmem_cell_add(struct nvmem_cell *cell) 313eace75cfSSrinivas Kandagatla { 314c7235ee3SBartosz Golaszewski mutex_lock(&nvmem_mutex); 315c7235ee3SBartosz Golaszewski list_add_tail(&cell->node, &cell->nvmem->cells); 316c7235ee3SBartosz Golaszewski mutex_unlock(&nvmem_mutex); 317bee1138bSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_ADD, cell); 318eace75cfSSrinivas Kandagatla } 319eace75cfSSrinivas Kandagatla 320eace75cfSSrinivas Kandagatla static int nvmem_cell_info_to_nvmem_cell(struct nvmem_device *nvmem, 321eace75cfSSrinivas Kandagatla const struct nvmem_cell_info *info, 322eace75cfSSrinivas Kandagatla struct nvmem_cell *cell) 323eace75cfSSrinivas Kandagatla { 324eace75cfSSrinivas Kandagatla cell->nvmem = nvmem; 325eace75cfSSrinivas Kandagatla cell->offset = info->offset; 326eace75cfSSrinivas Kandagatla cell->bytes = info->bytes; 327eace75cfSSrinivas Kandagatla cell->name = info->name; 328eace75cfSSrinivas Kandagatla 329eace75cfSSrinivas Kandagatla cell->bit_offset = info->bit_offset; 330eace75cfSSrinivas Kandagatla cell->nbits = info->nbits; 331eace75cfSSrinivas Kandagatla 332eace75cfSSrinivas Kandagatla if (cell->nbits) 333eace75cfSSrinivas Kandagatla cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset, 334eace75cfSSrinivas Kandagatla BITS_PER_BYTE); 335eace75cfSSrinivas Kandagatla 336eace75cfSSrinivas Kandagatla if (!IS_ALIGNED(cell->offset, nvmem->stride)) { 337eace75cfSSrinivas Kandagatla dev_err(&nvmem->dev, 338eace75cfSSrinivas Kandagatla "cell %s unaligned to nvmem stride %d\n", 339eace75cfSSrinivas Kandagatla cell->name, nvmem->stride); 340eace75cfSSrinivas Kandagatla return -EINVAL; 341eace75cfSSrinivas Kandagatla } 342eace75cfSSrinivas Kandagatla 343eace75cfSSrinivas Kandagatla return 0; 344eace75cfSSrinivas Kandagatla } 345eace75cfSSrinivas Kandagatla 346b3db17e4SAndrew Lunn /** 347b3db17e4SAndrew Lunn * nvmem_add_cells() - Add cell information to an nvmem device 348b3db17e4SAndrew Lunn * 349b3db17e4SAndrew Lunn * @nvmem: nvmem device to add cells to. 350b3db17e4SAndrew Lunn * @info: nvmem cell info to add to the device 351b3db17e4SAndrew Lunn * @ncells: number of cells in info 352b3db17e4SAndrew Lunn * 353b3db17e4SAndrew Lunn * Return: 0 or negative error code on failure. 354b3db17e4SAndrew Lunn */ 355b3db17e4SAndrew Lunn int nvmem_add_cells(struct nvmem_device *nvmem, 356b3db17e4SAndrew Lunn const struct nvmem_cell_info *info, 357b3db17e4SAndrew Lunn int ncells) 358eace75cfSSrinivas Kandagatla { 359eace75cfSSrinivas Kandagatla struct nvmem_cell **cells; 360eace75cfSSrinivas Kandagatla int i, rval; 361eace75cfSSrinivas Kandagatla 362b3db17e4SAndrew Lunn cells = kcalloc(ncells, sizeof(*cells), GFP_KERNEL); 363eace75cfSSrinivas Kandagatla if (!cells) 364eace75cfSSrinivas Kandagatla return -ENOMEM; 365eace75cfSSrinivas Kandagatla 366b3db17e4SAndrew Lunn for (i = 0; i < ncells; i++) { 367eace75cfSSrinivas Kandagatla cells[i] = kzalloc(sizeof(**cells), GFP_KERNEL); 368eace75cfSSrinivas Kandagatla if (!cells[i]) { 369eace75cfSSrinivas Kandagatla rval = -ENOMEM; 370eace75cfSSrinivas Kandagatla goto err; 371eace75cfSSrinivas Kandagatla } 372eace75cfSSrinivas Kandagatla 373eace75cfSSrinivas Kandagatla rval = nvmem_cell_info_to_nvmem_cell(nvmem, &info[i], cells[i]); 374287980e4SArnd Bergmann if (rval) { 375eace75cfSSrinivas Kandagatla kfree(cells[i]); 376eace75cfSSrinivas Kandagatla goto err; 377eace75cfSSrinivas Kandagatla } 378eace75cfSSrinivas Kandagatla 379eace75cfSSrinivas Kandagatla nvmem_cell_add(cells[i]); 380eace75cfSSrinivas Kandagatla } 381eace75cfSSrinivas Kandagatla 382eace75cfSSrinivas Kandagatla /* remove tmp array */ 383eace75cfSSrinivas Kandagatla kfree(cells); 384eace75cfSSrinivas Kandagatla 385eace75cfSSrinivas Kandagatla return 0; 386eace75cfSSrinivas Kandagatla err: 387dfdf1414SRasmus Villemoes while (i--) 388eace75cfSSrinivas Kandagatla nvmem_cell_drop(cells[i]); 389eace75cfSSrinivas Kandagatla 390dfdf1414SRasmus Villemoes kfree(cells); 391dfdf1414SRasmus Villemoes 392eace75cfSSrinivas Kandagatla return rval; 393eace75cfSSrinivas Kandagatla } 394b3db17e4SAndrew Lunn EXPORT_SYMBOL_GPL(nvmem_add_cells); 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); 551e888d445SBartosz Golaszewski cell->name = child->name; 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. */ 568e888d445SBartosz Golaszewski kfree(cell); 569e888d445SBartosz Golaszewski return -EINVAL; 570e888d445SBartosz Golaszewski } 571e888d445SBartosz Golaszewski 572e888d445SBartosz Golaszewski nvmem_cell_add(cell); 573e888d445SBartosz Golaszewski } 574e888d445SBartosz Golaszewski 575e888d445SBartosz Golaszewski return 0; 576e888d445SBartosz Golaszewski } 577e888d445SBartosz Golaszewski 578eace75cfSSrinivas Kandagatla /** 579eace75cfSSrinivas Kandagatla * nvmem_register() - Register a nvmem device for given nvmem_config. 580eace75cfSSrinivas Kandagatla * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem 581eace75cfSSrinivas Kandagatla * 582eace75cfSSrinivas Kandagatla * @config: nvmem device configuration with which nvmem device is created. 583eace75cfSSrinivas Kandagatla * 584eace75cfSSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device 585eace75cfSSrinivas Kandagatla * on success. 586eace75cfSSrinivas Kandagatla */ 587eace75cfSSrinivas Kandagatla 588eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem_register(const struct nvmem_config *config) 589eace75cfSSrinivas Kandagatla { 590eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem; 591eace75cfSSrinivas Kandagatla int rval; 592eace75cfSSrinivas Kandagatla 593eace75cfSSrinivas Kandagatla if (!config->dev) 594eace75cfSSrinivas Kandagatla return ERR_PTR(-EINVAL); 595eace75cfSSrinivas Kandagatla 596eace75cfSSrinivas Kandagatla nvmem = kzalloc(sizeof(*nvmem), GFP_KERNEL); 597eace75cfSSrinivas Kandagatla if (!nvmem) 598eace75cfSSrinivas Kandagatla return ERR_PTR(-ENOMEM); 599eace75cfSSrinivas Kandagatla 600eace75cfSSrinivas Kandagatla rval = ida_simple_get(&nvmem_ida, 0, 0, GFP_KERNEL); 601eace75cfSSrinivas Kandagatla if (rval < 0) { 602eace75cfSSrinivas Kandagatla kfree(nvmem); 603eace75cfSSrinivas Kandagatla return ERR_PTR(rval); 604eace75cfSSrinivas Kandagatla } 605eace75cfSSrinivas Kandagatla 606c1de7f43SBartosz Golaszewski kref_init(&nvmem->refcnt); 607c7235ee3SBartosz Golaszewski INIT_LIST_HEAD(&nvmem->cells); 608c1de7f43SBartosz Golaszewski 609eace75cfSSrinivas Kandagatla nvmem->id = rval; 610eace75cfSSrinivas Kandagatla nvmem->owner = config->owner; 61117eb18d6SMasahiro Yamada if (!nvmem->owner && config->dev->driver) 61217eb18d6SMasahiro Yamada nvmem->owner = config->dev->driver->owner; 61399897efdSHeiner Kallweit nvmem->stride = config->stride ?: 1; 61499897efdSHeiner Kallweit nvmem->word_size = config->word_size ?: 1; 615795ddd18SSrinivas Kandagatla nvmem->size = config->size; 616eace75cfSSrinivas Kandagatla nvmem->dev.type = &nvmem_provider_type; 617eace75cfSSrinivas Kandagatla nvmem->dev.bus = &nvmem_bus_type; 618eace75cfSSrinivas Kandagatla nvmem->dev.parent = config->dev; 619795ddd18SSrinivas Kandagatla nvmem->priv = config->priv; 620795ddd18SSrinivas Kandagatla nvmem->reg_read = config->reg_read; 621795ddd18SSrinivas Kandagatla nvmem->reg_write = config->reg_write; 622fc2f9970SHeiner Kallweit nvmem->dev.of_node = config->dev->of_node; 623fd0f4906SAndrey Smirnov 624fd0f4906SAndrey Smirnov if (config->id == -1 && config->name) { 625fd0f4906SAndrey Smirnov dev_set_name(&nvmem->dev, "%s", config->name); 626fd0f4906SAndrey Smirnov } else { 627eace75cfSSrinivas Kandagatla dev_set_name(&nvmem->dev, "%s%d", 6285253193dSAban Bedel config->name ? : "nvmem", 6295253193dSAban Bedel config->name ? config->id : nvmem->id); 630fd0f4906SAndrey Smirnov } 631eace75cfSSrinivas Kandagatla 632fc2f9970SHeiner Kallweit nvmem->read_only = device_property_present(config->dev, "read-only") | 633eace75cfSSrinivas Kandagatla config->read_only; 634eace75cfSSrinivas Kandagatla 635811b0d65SAndrew Lunn if (config->root_only) 636811b0d65SAndrew Lunn nvmem->dev.groups = nvmem->read_only ? 637811b0d65SAndrew Lunn nvmem_ro_root_dev_groups : 638811b0d65SAndrew Lunn nvmem_rw_root_dev_groups; 639811b0d65SAndrew Lunn else 640811b0d65SAndrew Lunn nvmem->dev.groups = nvmem->read_only ? 641811b0d65SAndrew Lunn nvmem_ro_dev_groups : 642eace75cfSSrinivas Kandagatla nvmem_rw_dev_groups; 643eace75cfSSrinivas Kandagatla 644eace75cfSSrinivas Kandagatla device_initialize(&nvmem->dev); 645eace75cfSSrinivas Kandagatla 646eace75cfSSrinivas Kandagatla dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name); 647eace75cfSSrinivas Kandagatla 648eace75cfSSrinivas Kandagatla rval = device_add(&nvmem->dev); 649b6c217abSAndrew Lunn if (rval) 6503360acdfSJohan Hovold goto err_put_device; 651b6c217abSAndrew Lunn 652b6c217abSAndrew Lunn if (config->compat) { 653b6c217abSAndrew Lunn rval = nvmem_setup_compat(nvmem, config); 654b6c217abSAndrew Lunn if (rval) 6553360acdfSJohan Hovold goto err_device_del; 656eace75cfSSrinivas Kandagatla } 657eace75cfSSrinivas Kandagatla 658fa72d847SBartosz Golaszewski if (config->cells) { 659fa72d847SBartosz Golaszewski rval = nvmem_add_cells(nvmem, config->cells, config->ncells); 660fa72d847SBartosz Golaszewski if (rval) 661fa72d847SBartosz Golaszewski goto err_teardown_compat; 662fa72d847SBartosz Golaszewski } 663eace75cfSSrinivas Kandagatla 664b985f4cbSBartosz Golaszewski rval = nvmem_add_cells_from_table(nvmem); 665b985f4cbSBartosz Golaszewski if (rval) 666b985f4cbSBartosz Golaszewski goto err_remove_cells; 667b985f4cbSBartosz Golaszewski 668e888d445SBartosz Golaszewski rval = nvmem_add_cells_from_of(nvmem); 669e888d445SBartosz Golaszewski if (rval) 670e888d445SBartosz Golaszewski goto err_remove_cells; 671e888d445SBartosz Golaszewski 672bee1138bSBartosz Golaszewski rval = blocking_notifier_call_chain(&nvmem_notifier, NVMEM_ADD, nvmem); 673bee1138bSBartosz Golaszewski if (rval) 674bee1138bSBartosz Golaszewski goto err_remove_cells; 675bee1138bSBartosz Golaszewski 676eace75cfSSrinivas Kandagatla return nvmem; 6773360acdfSJohan Hovold 678b985f4cbSBartosz Golaszewski err_remove_cells: 679b985f4cbSBartosz Golaszewski nvmem_device_remove_all_cells(nvmem); 680fa72d847SBartosz Golaszewski err_teardown_compat: 681fa72d847SBartosz Golaszewski if (config->compat) 682fa72d847SBartosz Golaszewski device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); 6833360acdfSJohan Hovold err_device_del: 6843360acdfSJohan Hovold device_del(&nvmem->dev); 6853360acdfSJohan Hovold err_put_device: 6863360acdfSJohan Hovold put_device(&nvmem->dev); 6873360acdfSJohan Hovold 688b6c217abSAndrew Lunn return ERR_PTR(rval); 689eace75cfSSrinivas Kandagatla } 690eace75cfSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_register); 691eace75cfSSrinivas Kandagatla 692c1de7f43SBartosz Golaszewski static void nvmem_device_release(struct kref *kref) 693c1de7f43SBartosz Golaszewski { 694c1de7f43SBartosz Golaszewski struct nvmem_device *nvmem; 695c1de7f43SBartosz Golaszewski 696c1de7f43SBartosz Golaszewski nvmem = container_of(kref, struct nvmem_device, refcnt); 697c1de7f43SBartosz Golaszewski 698bee1138bSBartosz Golaszewski blocking_notifier_call_chain(&nvmem_notifier, NVMEM_REMOVE, nvmem); 699bee1138bSBartosz Golaszewski 700c1de7f43SBartosz Golaszewski if (nvmem->flags & FLAG_COMPAT) 701c1de7f43SBartosz Golaszewski device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); 702c1de7f43SBartosz Golaszewski 703c1de7f43SBartosz Golaszewski nvmem_device_remove_all_cells(nvmem); 704c1de7f43SBartosz Golaszewski device_del(&nvmem->dev); 705c1de7f43SBartosz Golaszewski put_device(&nvmem->dev); 706c1de7f43SBartosz Golaszewski } 707c1de7f43SBartosz Golaszewski 708eace75cfSSrinivas Kandagatla /** 709eace75cfSSrinivas Kandagatla * nvmem_unregister() - Unregister previously registered nvmem device 710eace75cfSSrinivas Kandagatla * 711eace75cfSSrinivas Kandagatla * @nvmem: Pointer to previously registered nvmem device. 712eace75cfSSrinivas Kandagatla */ 713bf58e882SBartosz Golaszewski void nvmem_unregister(struct nvmem_device *nvmem) 714eace75cfSSrinivas Kandagatla { 715c1de7f43SBartosz Golaszewski kref_put(&nvmem->refcnt, nvmem_device_release); 716eace75cfSSrinivas Kandagatla } 717eace75cfSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_unregister); 718eace75cfSSrinivas Kandagatla 719f1f50ecaSAndrey Smirnov static void devm_nvmem_release(struct device *dev, void *res) 720f1f50ecaSAndrey Smirnov { 721bf58e882SBartosz Golaszewski nvmem_unregister(*(struct nvmem_device **)res); 722f1f50ecaSAndrey Smirnov } 723f1f50ecaSAndrey Smirnov 724f1f50ecaSAndrey Smirnov /** 725f1f50ecaSAndrey Smirnov * devm_nvmem_register() - Register a managed nvmem device for given 726f1f50ecaSAndrey Smirnov * nvmem_config. 727f1f50ecaSAndrey Smirnov * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem 728f1f50ecaSAndrey Smirnov * 729b378c779SSrinivas Kandagatla * @dev: Device that uses the nvmem device. 730f1f50ecaSAndrey Smirnov * @config: nvmem device configuration with which nvmem device is created. 731f1f50ecaSAndrey Smirnov * 732f1f50ecaSAndrey Smirnov * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device 733f1f50ecaSAndrey Smirnov * on success. 734f1f50ecaSAndrey Smirnov */ 735f1f50ecaSAndrey Smirnov struct nvmem_device *devm_nvmem_register(struct device *dev, 736f1f50ecaSAndrey Smirnov const struct nvmem_config *config) 737f1f50ecaSAndrey Smirnov { 738f1f50ecaSAndrey Smirnov struct nvmem_device **ptr, *nvmem; 739f1f50ecaSAndrey Smirnov 740f1f50ecaSAndrey Smirnov ptr = devres_alloc(devm_nvmem_release, sizeof(*ptr), GFP_KERNEL); 741f1f50ecaSAndrey Smirnov if (!ptr) 742f1f50ecaSAndrey Smirnov return ERR_PTR(-ENOMEM); 743f1f50ecaSAndrey Smirnov 744f1f50ecaSAndrey Smirnov nvmem = nvmem_register(config); 745f1f50ecaSAndrey Smirnov 746f1f50ecaSAndrey Smirnov if (!IS_ERR(nvmem)) { 747f1f50ecaSAndrey Smirnov *ptr = nvmem; 748f1f50ecaSAndrey Smirnov devres_add(dev, ptr); 749f1f50ecaSAndrey Smirnov } else { 750f1f50ecaSAndrey Smirnov devres_free(ptr); 751f1f50ecaSAndrey Smirnov } 752f1f50ecaSAndrey Smirnov 753f1f50ecaSAndrey Smirnov return nvmem; 754f1f50ecaSAndrey Smirnov } 755f1f50ecaSAndrey Smirnov EXPORT_SYMBOL_GPL(devm_nvmem_register); 756f1f50ecaSAndrey Smirnov 757f1f50ecaSAndrey Smirnov static int devm_nvmem_match(struct device *dev, void *res, void *data) 758f1f50ecaSAndrey Smirnov { 759f1f50ecaSAndrey Smirnov struct nvmem_device **r = res; 760f1f50ecaSAndrey Smirnov 761f1f50ecaSAndrey Smirnov return *r == data; 762f1f50ecaSAndrey Smirnov } 763f1f50ecaSAndrey Smirnov 764f1f50ecaSAndrey Smirnov /** 765f1f50ecaSAndrey Smirnov * devm_nvmem_unregister() - Unregister previously registered managed nvmem 766f1f50ecaSAndrey Smirnov * device. 767f1f50ecaSAndrey Smirnov * 768b378c779SSrinivas Kandagatla * @dev: Device that uses the nvmem device. 769f1f50ecaSAndrey Smirnov * @nvmem: Pointer to previously registered nvmem device. 770f1f50ecaSAndrey Smirnov * 771f1f50ecaSAndrey Smirnov * Return: Will be an negative on error or a zero on success. 772f1f50ecaSAndrey Smirnov */ 773f1f50ecaSAndrey Smirnov int devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem) 774f1f50ecaSAndrey Smirnov { 775f1f50ecaSAndrey Smirnov return devres_release(dev, devm_nvmem_release, devm_nvmem_match, nvmem); 776f1f50ecaSAndrey Smirnov } 777f1f50ecaSAndrey Smirnov EXPORT_SYMBOL(devm_nvmem_unregister); 778f1f50ecaSAndrey Smirnov 77969aba794SSrinivas Kandagatla static struct nvmem_device *__nvmem_device_get(struct device_node *np, 780506157beSBartosz Golaszewski const char *nvmem_name) 78169aba794SSrinivas Kandagatla { 78269aba794SSrinivas Kandagatla struct nvmem_device *nvmem = NULL; 78369aba794SSrinivas Kandagatla 784c7235ee3SBartosz Golaszewski mutex_lock(&nvmem_mutex); 785506157beSBartosz Golaszewski nvmem = np ? of_nvmem_find(np) : nvmem_find(nvmem_name); 78669aba794SSrinivas Kandagatla mutex_unlock(&nvmem_mutex); 787c7235ee3SBartosz Golaszewski if (!nvmem) 788c7235ee3SBartosz Golaszewski return ERR_PTR(-EPROBE_DEFER); 78969aba794SSrinivas Kandagatla 79069aba794SSrinivas Kandagatla if (!try_module_get(nvmem->owner)) { 79169aba794SSrinivas Kandagatla dev_err(&nvmem->dev, 79269aba794SSrinivas Kandagatla "could not increase module refcount for cell %s\n", 7935db652c9SBartosz Golaszewski nvmem_dev_name(nvmem)); 79469aba794SSrinivas Kandagatla 79569aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 79669aba794SSrinivas Kandagatla } 79769aba794SSrinivas Kandagatla 798c1de7f43SBartosz Golaszewski kref_get(&nvmem->refcnt); 799c1de7f43SBartosz Golaszewski 80069aba794SSrinivas Kandagatla return nvmem; 80169aba794SSrinivas Kandagatla } 80269aba794SSrinivas Kandagatla 80369aba794SSrinivas Kandagatla static void __nvmem_device_put(struct nvmem_device *nvmem) 80469aba794SSrinivas Kandagatla { 80569aba794SSrinivas Kandagatla module_put(nvmem->owner); 806c1de7f43SBartosz Golaszewski kref_put(&nvmem->refcnt, nvmem_device_release); 80769aba794SSrinivas Kandagatla } 80869aba794SSrinivas Kandagatla 809e701c67cSMasahiro Yamada #if IS_ENABLED(CONFIG_OF) 810e2a5402eSSrinivas Kandagatla /** 811e2a5402eSSrinivas Kandagatla * of_nvmem_device_get() - Get nvmem device from a given id 812e2a5402eSSrinivas Kandagatla * 81329143268SVivek Gautam * @np: Device tree node that uses the nvmem device. 814e2a5402eSSrinivas Kandagatla * @id: nvmem name from nvmem-names property. 815e2a5402eSSrinivas Kandagatla * 816e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device 817e2a5402eSSrinivas Kandagatla * on success. 818e2a5402eSSrinivas Kandagatla */ 819e2a5402eSSrinivas Kandagatla struct nvmem_device *of_nvmem_device_get(struct device_node *np, const char *id) 820e2a5402eSSrinivas Kandagatla { 821e2a5402eSSrinivas Kandagatla 822e2a5402eSSrinivas Kandagatla struct device_node *nvmem_np; 823e2a5402eSSrinivas Kandagatla int index; 824e2a5402eSSrinivas Kandagatla 825e2a5402eSSrinivas Kandagatla index = of_property_match_string(np, "nvmem-names", id); 826e2a5402eSSrinivas Kandagatla 827e2a5402eSSrinivas Kandagatla nvmem_np = of_parse_phandle(np, "nvmem", index); 828e2a5402eSSrinivas Kandagatla if (!nvmem_np) 829e2a5402eSSrinivas Kandagatla return ERR_PTR(-EINVAL); 830e2a5402eSSrinivas Kandagatla 831506157beSBartosz Golaszewski return __nvmem_device_get(nvmem_np, NULL); 832e2a5402eSSrinivas Kandagatla } 833e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_nvmem_device_get); 834e2a5402eSSrinivas Kandagatla #endif 835e2a5402eSSrinivas Kandagatla 836e2a5402eSSrinivas Kandagatla /** 837e2a5402eSSrinivas Kandagatla * nvmem_device_get() - Get nvmem device from a given id 838e2a5402eSSrinivas Kandagatla * 83929143268SVivek Gautam * @dev: Device that uses the nvmem device. 84029143268SVivek Gautam * @dev_name: name of the requested nvmem device. 841e2a5402eSSrinivas Kandagatla * 842e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device 843e2a5402eSSrinivas Kandagatla * on success. 844e2a5402eSSrinivas Kandagatla */ 845e2a5402eSSrinivas Kandagatla struct nvmem_device *nvmem_device_get(struct device *dev, const char *dev_name) 846e2a5402eSSrinivas Kandagatla { 847e2a5402eSSrinivas Kandagatla if (dev->of_node) { /* try dt first */ 848e2a5402eSSrinivas Kandagatla struct nvmem_device *nvmem; 849e2a5402eSSrinivas Kandagatla 850e2a5402eSSrinivas Kandagatla nvmem = of_nvmem_device_get(dev->of_node, dev_name); 851e2a5402eSSrinivas Kandagatla 852e2a5402eSSrinivas Kandagatla if (!IS_ERR(nvmem) || PTR_ERR(nvmem) == -EPROBE_DEFER) 853e2a5402eSSrinivas Kandagatla return nvmem; 854e2a5402eSSrinivas Kandagatla 855e2a5402eSSrinivas Kandagatla } 856e2a5402eSSrinivas Kandagatla 857e2a5402eSSrinivas Kandagatla return nvmem_find(dev_name); 858e2a5402eSSrinivas Kandagatla } 859e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_get); 860e2a5402eSSrinivas Kandagatla 861e2a5402eSSrinivas Kandagatla static int devm_nvmem_device_match(struct device *dev, void *res, void *data) 862e2a5402eSSrinivas Kandagatla { 863e2a5402eSSrinivas Kandagatla struct nvmem_device **nvmem = res; 864e2a5402eSSrinivas Kandagatla 865e2a5402eSSrinivas Kandagatla if (WARN_ON(!nvmem || !*nvmem)) 866e2a5402eSSrinivas Kandagatla return 0; 867e2a5402eSSrinivas Kandagatla 868e2a5402eSSrinivas Kandagatla return *nvmem == data; 869e2a5402eSSrinivas Kandagatla } 870e2a5402eSSrinivas Kandagatla 871e2a5402eSSrinivas Kandagatla static void devm_nvmem_device_release(struct device *dev, void *res) 872e2a5402eSSrinivas Kandagatla { 873e2a5402eSSrinivas Kandagatla nvmem_device_put(*(struct nvmem_device **)res); 874e2a5402eSSrinivas Kandagatla } 875e2a5402eSSrinivas Kandagatla 876e2a5402eSSrinivas Kandagatla /** 877e2a5402eSSrinivas Kandagatla * devm_nvmem_device_put() - put alredy got nvmem device 878e2a5402eSSrinivas Kandagatla * 87929143268SVivek Gautam * @dev: Device that uses the nvmem device. 880e2a5402eSSrinivas Kandagatla * @nvmem: pointer to nvmem device allocated by devm_nvmem_cell_get(), 881e2a5402eSSrinivas Kandagatla * that needs to be released. 882e2a5402eSSrinivas Kandagatla */ 883e2a5402eSSrinivas Kandagatla void devm_nvmem_device_put(struct device *dev, struct nvmem_device *nvmem) 884e2a5402eSSrinivas Kandagatla { 885e2a5402eSSrinivas Kandagatla int ret; 886e2a5402eSSrinivas Kandagatla 887e2a5402eSSrinivas Kandagatla ret = devres_release(dev, devm_nvmem_device_release, 888e2a5402eSSrinivas Kandagatla devm_nvmem_device_match, nvmem); 889e2a5402eSSrinivas Kandagatla 890e2a5402eSSrinivas Kandagatla WARN_ON(ret); 891e2a5402eSSrinivas Kandagatla } 892e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_device_put); 893e2a5402eSSrinivas Kandagatla 894e2a5402eSSrinivas Kandagatla /** 895e2a5402eSSrinivas Kandagatla * nvmem_device_put() - put alredy got nvmem device 896e2a5402eSSrinivas Kandagatla * 897e2a5402eSSrinivas Kandagatla * @nvmem: pointer to nvmem device that needs to be released. 898e2a5402eSSrinivas Kandagatla */ 899e2a5402eSSrinivas Kandagatla void nvmem_device_put(struct nvmem_device *nvmem) 900e2a5402eSSrinivas Kandagatla { 901e2a5402eSSrinivas Kandagatla __nvmem_device_put(nvmem); 902e2a5402eSSrinivas Kandagatla } 903e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_put); 904e2a5402eSSrinivas Kandagatla 905e2a5402eSSrinivas Kandagatla /** 906e2a5402eSSrinivas Kandagatla * devm_nvmem_device_get() - Get nvmem cell of device form a given id 907e2a5402eSSrinivas Kandagatla * 90829143268SVivek Gautam * @dev: Device that requests the nvmem device. 90929143268SVivek Gautam * @id: name id for the requested nvmem device. 910e2a5402eSSrinivas Kandagatla * 911e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_cell 912e2a5402eSSrinivas Kandagatla * on success. The nvmem_cell will be freed by the automatically once the 913e2a5402eSSrinivas Kandagatla * device is freed. 914e2a5402eSSrinivas Kandagatla */ 915e2a5402eSSrinivas Kandagatla struct nvmem_device *devm_nvmem_device_get(struct device *dev, const char *id) 916e2a5402eSSrinivas Kandagatla { 917e2a5402eSSrinivas Kandagatla struct nvmem_device **ptr, *nvmem; 918e2a5402eSSrinivas Kandagatla 919e2a5402eSSrinivas Kandagatla ptr = devres_alloc(devm_nvmem_device_release, sizeof(*ptr), GFP_KERNEL); 920e2a5402eSSrinivas Kandagatla if (!ptr) 921e2a5402eSSrinivas Kandagatla return ERR_PTR(-ENOMEM); 922e2a5402eSSrinivas Kandagatla 923e2a5402eSSrinivas Kandagatla nvmem = nvmem_device_get(dev, id); 924e2a5402eSSrinivas Kandagatla if (!IS_ERR(nvmem)) { 925e2a5402eSSrinivas Kandagatla *ptr = nvmem; 926e2a5402eSSrinivas Kandagatla devres_add(dev, ptr); 927e2a5402eSSrinivas Kandagatla } else { 928e2a5402eSSrinivas Kandagatla devres_free(ptr); 929e2a5402eSSrinivas Kandagatla } 930e2a5402eSSrinivas Kandagatla 931e2a5402eSSrinivas Kandagatla return nvmem; 932e2a5402eSSrinivas Kandagatla } 933e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_device_get); 934e2a5402eSSrinivas Kandagatla 935506157beSBartosz Golaszewski static struct nvmem_cell * 936506157beSBartosz Golaszewski nvmem_cell_get_from_lookup(struct device *dev, const char *con_id) 93769aba794SSrinivas Kandagatla { 938506157beSBartosz Golaszewski struct nvmem_cell *cell = ERR_PTR(-ENOENT); 939506157beSBartosz Golaszewski struct nvmem_cell_lookup *lookup; 94069aba794SSrinivas Kandagatla struct nvmem_device *nvmem; 941506157beSBartosz Golaszewski const char *dev_id; 94269aba794SSrinivas Kandagatla 943506157beSBartosz Golaszewski if (!dev) 944506157beSBartosz Golaszewski return ERR_PTR(-EINVAL); 94569aba794SSrinivas Kandagatla 946506157beSBartosz Golaszewski dev_id = dev_name(dev); 947506157beSBartosz Golaszewski 948506157beSBartosz Golaszewski mutex_lock(&nvmem_lookup_mutex); 949506157beSBartosz Golaszewski 950506157beSBartosz Golaszewski list_for_each_entry(lookup, &nvmem_lookup_list, node) { 951506157beSBartosz Golaszewski if ((strcmp(lookup->dev_id, dev_id) == 0) && 952506157beSBartosz Golaszewski (strcmp(lookup->con_id, con_id) == 0)) { 953506157beSBartosz Golaszewski /* This is the right entry. */ 954506157beSBartosz Golaszewski nvmem = __nvmem_device_get(NULL, lookup->nvmem_name); 955506157beSBartosz Golaszewski if (!nvmem) { 956506157beSBartosz Golaszewski /* Provider may not be registered yet. */ 957506157beSBartosz Golaszewski cell = ERR_PTR(-EPROBE_DEFER); 958506157beSBartosz Golaszewski goto out; 959506157beSBartosz Golaszewski } 960506157beSBartosz Golaszewski 961506157beSBartosz Golaszewski cell = nvmem_find_cell_by_name(nvmem, 962506157beSBartosz Golaszewski lookup->cell_name); 963506157beSBartosz Golaszewski if (!cell) { 964506157beSBartosz Golaszewski __nvmem_device_put(nvmem); 965506157beSBartosz Golaszewski goto out; 966506157beSBartosz Golaszewski } 967506157beSBartosz Golaszewski } 968506157beSBartosz Golaszewski } 969506157beSBartosz Golaszewski 970506157beSBartosz Golaszewski out: 971506157beSBartosz Golaszewski mutex_unlock(&nvmem_lookup_mutex); 97269aba794SSrinivas Kandagatla return cell; 97369aba794SSrinivas Kandagatla } 97469aba794SSrinivas Kandagatla 975e701c67cSMasahiro Yamada #if IS_ENABLED(CONFIG_OF) 97669aba794SSrinivas Kandagatla /** 97769aba794SSrinivas Kandagatla * of_nvmem_cell_get() - Get a nvmem cell from given device node and cell id 97869aba794SSrinivas Kandagatla * 97929143268SVivek Gautam * @np: Device tree node that uses the nvmem cell. 980*165589f0SBartosz Golaszewski * @id: nvmem cell name from nvmem-cell-names property, or NULL 981fd0c478cSVivek Gautam * for the cell at index 0 (the lone cell with no accompanying 982fd0c478cSVivek Gautam * nvmem-cell-names property). 98369aba794SSrinivas Kandagatla * 98469aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 98569aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 98669aba794SSrinivas Kandagatla * nvmem_cell_put(). 98769aba794SSrinivas Kandagatla */ 988*165589f0SBartosz Golaszewski struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *id) 98969aba794SSrinivas Kandagatla { 99069aba794SSrinivas Kandagatla struct device_node *cell_np, *nvmem_np; 99169aba794SSrinivas Kandagatla struct nvmem_device *nvmem; 992e888d445SBartosz Golaszewski struct nvmem_cell *cell; 993fd0c478cSVivek Gautam int index = 0; 99469aba794SSrinivas Kandagatla 995fd0c478cSVivek Gautam /* if cell name exists, find index to the name */ 996*165589f0SBartosz Golaszewski if (id) 997*165589f0SBartosz Golaszewski index = of_property_match_string(np, "nvmem-cell-names", id); 99869aba794SSrinivas Kandagatla 99969aba794SSrinivas Kandagatla cell_np = of_parse_phandle(np, "nvmem-cells", index); 100069aba794SSrinivas Kandagatla if (!cell_np) 100169aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 100269aba794SSrinivas Kandagatla 100369aba794SSrinivas Kandagatla nvmem_np = of_get_next_parent(cell_np); 100469aba794SSrinivas Kandagatla if (!nvmem_np) 100569aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 100669aba794SSrinivas Kandagatla 1007506157beSBartosz Golaszewski nvmem = __nvmem_device_get(nvmem_np, NULL); 1008aad8d097SMasahiro Yamada of_node_put(nvmem_np); 100969aba794SSrinivas Kandagatla if (IS_ERR(nvmem)) 101069aba794SSrinivas Kandagatla return ERR_CAST(nvmem); 101169aba794SSrinivas Kandagatla 1012e888d445SBartosz Golaszewski cell = nvmem_find_cell_by_index(nvmem, index); 101369aba794SSrinivas Kandagatla if (!cell) { 1014e888d445SBartosz Golaszewski __nvmem_device_put(nvmem); 1015e888d445SBartosz Golaszewski return ERR_PTR(-ENOENT); 101669aba794SSrinivas Kandagatla } 101769aba794SSrinivas Kandagatla 101869aba794SSrinivas Kandagatla return cell; 101969aba794SSrinivas Kandagatla } 102069aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_nvmem_cell_get); 102169aba794SSrinivas Kandagatla #endif 102269aba794SSrinivas Kandagatla 102369aba794SSrinivas Kandagatla /** 102469aba794SSrinivas Kandagatla * nvmem_cell_get() - Get nvmem cell of device form a given cell name 102569aba794SSrinivas Kandagatla * 102629143268SVivek Gautam * @dev: Device that requests the nvmem cell. 1027*165589f0SBartosz Golaszewski * @id: nvmem cell name to get (this corresponds with the name from the 1028*165589f0SBartosz Golaszewski * nvmem-cell-names property for DT systems and with the con_id from 1029*165589f0SBartosz Golaszewski * the lookup entry for non-DT systems). 103069aba794SSrinivas Kandagatla * 103169aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 103269aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 103369aba794SSrinivas Kandagatla * nvmem_cell_put(). 103469aba794SSrinivas Kandagatla */ 1035*165589f0SBartosz Golaszewski struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *id) 103669aba794SSrinivas Kandagatla { 103769aba794SSrinivas Kandagatla struct nvmem_cell *cell; 103869aba794SSrinivas Kandagatla 103969aba794SSrinivas Kandagatla if (dev->of_node) { /* try dt first */ 1040*165589f0SBartosz Golaszewski cell = of_nvmem_cell_get(dev->of_node, id); 104169aba794SSrinivas Kandagatla if (!IS_ERR(cell) || PTR_ERR(cell) == -EPROBE_DEFER) 104269aba794SSrinivas Kandagatla return cell; 104369aba794SSrinivas Kandagatla } 104469aba794SSrinivas Kandagatla 1045*165589f0SBartosz Golaszewski /* NULL cell id only allowed for device tree; invalid otherwise */ 1046*165589f0SBartosz Golaszewski if (!id) 104787ed1405SDouglas Anderson return ERR_PTR(-EINVAL); 104887ed1405SDouglas Anderson 1049*165589f0SBartosz Golaszewski return nvmem_cell_get_from_lookup(dev, id); 105069aba794SSrinivas Kandagatla } 105169aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_get); 105269aba794SSrinivas Kandagatla 105369aba794SSrinivas Kandagatla static void devm_nvmem_cell_release(struct device *dev, void *res) 105469aba794SSrinivas Kandagatla { 105569aba794SSrinivas Kandagatla nvmem_cell_put(*(struct nvmem_cell **)res); 105669aba794SSrinivas Kandagatla } 105769aba794SSrinivas Kandagatla 105869aba794SSrinivas Kandagatla /** 105969aba794SSrinivas Kandagatla * devm_nvmem_cell_get() - Get nvmem cell of device form a given id 106069aba794SSrinivas Kandagatla * 106129143268SVivek Gautam * @dev: Device that requests the nvmem cell. 106229143268SVivek Gautam * @id: nvmem cell name id to get. 106369aba794SSrinivas Kandagatla * 106469aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 106569aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 106669aba794SSrinivas Kandagatla * automatically once the device is freed. 106769aba794SSrinivas Kandagatla */ 106869aba794SSrinivas Kandagatla struct nvmem_cell *devm_nvmem_cell_get(struct device *dev, const char *id) 106969aba794SSrinivas Kandagatla { 107069aba794SSrinivas Kandagatla struct nvmem_cell **ptr, *cell; 107169aba794SSrinivas Kandagatla 107269aba794SSrinivas Kandagatla ptr = devres_alloc(devm_nvmem_cell_release, sizeof(*ptr), GFP_KERNEL); 107369aba794SSrinivas Kandagatla if (!ptr) 107469aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 107569aba794SSrinivas Kandagatla 107669aba794SSrinivas Kandagatla cell = nvmem_cell_get(dev, id); 107769aba794SSrinivas Kandagatla if (!IS_ERR(cell)) { 107869aba794SSrinivas Kandagatla *ptr = cell; 107969aba794SSrinivas Kandagatla devres_add(dev, ptr); 108069aba794SSrinivas Kandagatla } else { 108169aba794SSrinivas Kandagatla devres_free(ptr); 108269aba794SSrinivas Kandagatla } 108369aba794SSrinivas Kandagatla 108469aba794SSrinivas Kandagatla return cell; 108569aba794SSrinivas Kandagatla } 108669aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_cell_get); 108769aba794SSrinivas Kandagatla 108869aba794SSrinivas Kandagatla static int devm_nvmem_cell_match(struct device *dev, void *res, void *data) 108969aba794SSrinivas Kandagatla { 109069aba794SSrinivas Kandagatla struct nvmem_cell **c = res; 109169aba794SSrinivas Kandagatla 109269aba794SSrinivas Kandagatla if (WARN_ON(!c || !*c)) 109369aba794SSrinivas Kandagatla return 0; 109469aba794SSrinivas Kandagatla 109569aba794SSrinivas Kandagatla return *c == data; 109669aba794SSrinivas Kandagatla } 109769aba794SSrinivas Kandagatla 109869aba794SSrinivas Kandagatla /** 109969aba794SSrinivas Kandagatla * devm_nvmem_cell_put() - Release previously allocated nvmem cell 110069aba794SSrinivas Kandagatla * from devm_nvmem_cell_get. 110169aba794SSrinivas Kandagatla * 110229143268SVivek Gautam * @dev: Device that requests the nvmem cell. 110329143268SVivek Gautam * @cell: Previously allocated nvmem cell by devm_nvmem_cell_get(). 110469aba794SSrinivas Kandagatla */ 110569aba794SSrinivas Kandagatla void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell) 110669aba794SSrinivas Kandagatla { 110769aba794SSrinivas Kandagatla int ret; 110869aba794SSrinivas Kandagatla 110969aba794SSrinivas Kandagatla ret = devres_release(dev, devm_nvmem_cell_release, 111069aba794SSrinivas Kandagatla devm_nvmem_cell_match, cell); 111169aba794SSrinivas Kandagatla 111269aba794SSrinivas Kandagatla WARN_ON(ret); 111369aba794SSrinivas Kandagatla } 111469aba794SSrinivas Kandagatla EXPORT_SYMBOL(devm_nvmem_cell_put); 111569aba794SSrinivas Kandagatla 111669aba794SSrinivas Kandagatla /** 111769aba794SSrinivas Kandagatla * nvmem_cell_put() - Release previously allocated nvmem cell. 111869aba794SSrinivas Kandagatla * 111929143268SVivek Gautam * @cell: Previously allocated nvmem cell by nvmem_cell_get(). 112069aba794SSrinivas Kandagatla */ 112169aba794SSrinivas Kandagatla void nvmem_cell_put(struct nvmem_cell *cell) 112269aba794SSrinivas Kandagatla { 112369aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 112469aba794SSrinivas Kandagatla 112569aba794SSrinivas Kandagatla __nvmem_device_put(nvmem); 112669aba794SSrinivas Kandagatla } 112769aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_put); 112869aba794SSrinivas Kandagatla 1129f7c04f16SMasahiro Yamada static void nvmem_shift_read_buffer_in_place(struct nvmem_cell *cell, void *buf) 113069aba794SSrinivas Kandagatla { 113169aba794SSrinivas Kandagatla u8 *p, *b; 113269aba794SSrinivas Kandagatla int i, bit_offset = cell->bit_offset; 113369aba794SSrinivas Kandagatla 113469aba794SSrinivas Kandagatla p = b = buf; 113569aba794SSrinivas Kandagatla if (bit_offset) { 113669aba794SSrinivas Kandagatla /* First shift */ 113769aba794SSrinivas Kandagatla *b++ >>= bit_offset; 113869aba794SSrinivas Kandagatla 113969aba794SSrinivas Kandagatla /* setup rest of the bytes if any */ 114069aba794SSrinivas Kandagatla for (i = 1; i < cell->bytes; i++) { 114169aba794SSrinivas Kandagatla /* Get bits from next byte and shift them towards msb */ 114269aba794SSrinivas Kandagatla *p |= *b << (BITS_PER_BYTE - bit_offset); 114369aba794SSrinivas Kandagatla 114469aba794SSrinivas Kandagatla p = b; 114569aba794SSrinivas Kandagatla *b++ >>= bit_offset; 114669aba794SSrinivas Kandagatla } 114769aba794SSrinivas Kandagatla 114869aba794SSrinivas Kandagatla /* result fits in less bytes */ 114969aba794SSrinivas Kandagatla if (cell->bytes != DIV_ROUND_UP(cell->nbits, BITS_PER_BYTE)) 115069aba794SSrinivas Kandagatla *p-- = 0; 115169aba794SSrinivas Kandagatla } 115269aba794SSrinivas Kandagatla /* clear msb bits if any leftover in the last byte */ 115369aba794SSrinivas Kandagatla *p &= GENMASK((cell->nbits%BITS_PER_BYTE) - 1, 0); 115469aba794SSrinivas Kandagatla } 115569aba794SSrinivas Kandagatla 115669aba794SSrinivas Kandagatla static int __nvmem_cell_read(struct nvmem_device *nvmem, 115769aba794SSrinivas Kandagatla struct nvmem_cell *cell, 115869aba794SSrinivas Kandagatla void *buf, size_t *len) 115969aba794SSrinivas Kandagatla { 116069aba794SSrinivas Kandagatla int rc; 116169aba794SSrinivas Kandagatla 1162795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, cell->offset, buf, cell->bytes); 116369aba794SSrinivas Kandagatla 1164287980e4SArnd Bergmann if (rc) 116569aba794SSrinivas Kandagatla return rc; 116669aba794SSrinivas Kandagatla 116769aba794SSrinivas Kandagatla /* shift bits in-place */ 1168cbf854abSAxel Lin if (cell->bit_offset || cell->nbits) 116969aba794SSrinivas Kandagatla nvmem_shift_read_buffer_in_place(cell, buf); 117069aba794SSrinivas Kandagatla 11713b4a6877SVivek Gautam if (len) 117269aba794SSrinivas Kandagatla *len = cell->bytes; 117369aba794SSrinivas Kandagatla 117469aba794SSrinivas Kandagatla return 0; 117569aba794SSrinivas Kandagatla } 117669aba794SSrinivas Kandagatla 117769aba794SSrinivas Kandagatla /** 117869aba794SSrinivas Kandagatla * nvmem_cell_read() - Read a given nvmem cell 117969aba794SSrinivas Kandagatla * 118069aba794SSrinivas Kandagatla * @cell: nvmem cell to be read. 11813b4a6877SVivek Gautam * @len: pointer to length of cell which will be populated on successful read; 11823b4a6877SVivek Gautam * can be NULL. 118369aba794SSrinivas Kandagatla * 1184b577fafcSBrian Norris * Return: ERR_PTR() on error or a valid pointer to a buffer on success. The 1185b577fafcSBrian Norris * buffer should be freed by the consumer with a kfree(). 118669aba794SSrinivas Kandagatla */ 118769aba794SSrinivas Kandagatla void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len) 118869aba794SSrinivas Kandagatla { 118969aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 119069aba794SSrinivas Kandagatla u8 *buf; 119169aba794SSrinivas Kandagatla int rc; 119269aba794SSrinivas Kandagatla 1193795ddd18SSrinivas Kandagatla if (!nvmem) 119469aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 119569aba794SSrinivas Kandagatla 119669aba794SSrinivas Kandagatla buf = kzalloc(cell->bytes, GFP_KERNEL); 119769aba794SSrinivas Kandagatla if (!buf) 119869aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 119969aba794SSrinivas Kandagatla 120069aba794SSrinivas Kandagatla rc = __nvmem_cell_read(nvmem, cell, buf, len); 1201287980e4SArnd Bergmann if (rc) { 120269aba794SSrinivas Kandagatla kfree(buf); 120369aba794SSrinivas Kandagatla return ERR_PTR(rc); 120469aba794SSrinivas Kandagatla } 120569aba794SSrinivas Kandagatla 120669aba794SSrinivas Kandagatla return buf; 120769aba794SSrinivas Kandagatla } 120869aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_read); 120969aba794SSrinivas Kandagatla 1210f7c04f16SMasahiro Yamada static void *nvmem_cell_prepare_write_buffer(struct nvmem_cell *cell, 121169aba794SSrinivas Kandagatla u8 *_buf, int len) 121269aba794SSrinivas Kandagatla { 121369aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 121469aba794SSrinivas Kandagatla int i, rc, nbits, bit_offset = cell->bit_offset; 121569aba794SSrinivas Kandagatla u8 v, *p, *buf, *b, pbyte, pbits; 121669aba794SSrinivas Kandagatla 121769aba794SSrinivas Kandagatla nbits = cell->nbits; 121869aba794SSrinivas Kandagatla buf = kzalloc(cell->bytes, GFP_KERNEL); 121969aba794SSrinivas Kandagatla if (!buf) 122069aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 122169aba794SSrinivas Kandagatla 122269aba794SSrinivas Kandagatla memcpy(buf, _buf, len); 122369aba794SSrinivas Kandagatla p = b = buf; 122469aba794SSrinivas Kandagatla 122569aba794SSrinivas Kandagatla if (bit_offset) { 122669aba794SSrinivas Kandagatla pbyte = *b; 122769aba794SSrinivas Kandagatla *b <<= bit_offset; 122869aba794SSrinivas Kandagatla 122969aba794SSrinivas Kandagatla /* setup the first byte with lsb bits from nvmem */ 1230795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, cell->offset, &v, 1); 123150808bfcSMathieu Malaterre if (rc) 123250808bfcSMathieu Malaterre goto err; 123369aba794SSrinivas Kandagatla *b++ |= GENMASK(bit_offset - 1, 0) & v; 123469aba794SSrinivas Kandagatla 123569aba794SSrinivas Kandagatla /* setup rest of the byte if any */ 123669aba794SSrinivas Kandagatla for (i = 1; i < cell->bytes; i++) { 123769aba794SSrinivas Kandagatla /* Get last byte bits and shift them towards lsb */ 123869aba794SSrinivas Kandagatla pbits = pbyte >> (BITS_PER_BYTE - 1 - bit_offset); 123969aba794SSrinivas Kandagatla pbyte = *b; 124069aba794SSrinivas Kandagatla p = b; 124169aba794SSrinivas Kandagatla *b <<= bit_offset; 124269aba794SSrinivas Kandagatla *b++ |= pbits; 124369aba794SSrinivas Kandagatla } 124469aba794SSrinivas Kandagatla } 124569aba794SSrinivas Kandagatla 124669aba794SSrinivas Kandagatla /* if it's not end on byte boundary */ 124769aba794SSrinivas Kandagatla if ((nbits + bit_offset) % BITS_PER_BYTE) { 124869aba794SSrinivas Kandagatla /* setup the last byte with msb bits from nvmem */ 1249795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, 125069aba794SSrinivas Kandagatla cell->offset + cell->bytes - 1, &v, 1); 125150808bfcSMathieu Malaterre if (rc) 125250808bfcSMathieu Malaterre goto err; 125369aba794SSrinivas Kandagatla *p |= GENMASK(7, (nbits + bit_offset) % BITS_PER_BYTE) & v; 125469aba794SSrinivas Kandagatla 125569aba794SSrinivas Kandagatla } 125669aba794SSrinivas Kandagatla 125769aba794SSrinivas Kandagatla return buf; 125850808bfcSMathieu Malaterre err: 125950808bfcSMathieu Malaterre kfree(buf); 126050808bfcSMathieu Malaterre return ERR_PTR(rc); 126169aba794SSrinivas Kandagatla } 126269aba794SSrinivas Kandagatla 126369aba794SSrinivas Kandagatla /** 126469aba794SSrinivas Kandagatla * nvmem_cell_write() - Write to a given nvmem cell 126569aba794SSrinivas Kandagatla * 126669aba794SSrinivas Kandagatla * @cell: nvmem cell to be written. 126769aba794SSrinivas Kandagatla * @buf: Buffer to be written. 126869aba794SSrinivas Kandagatla * @len: length of buffer to be written to nvmem cell. 126969aba794SSrinivas Kandagatla * 127069aba794SSrinivas Kandagatla * Return: length of bytes written or negative on failure. 127169aba794SSrinivas Kandagatla */ 127269aba794SSrinivas Kandagatla int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len) 127369aba794SSrinivas Kandagatla { 127469aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 127569aba794SSrinivas Kandagatla int rc; 127669aba794SSrinivas Kandagatla 1277795ddd18SSrinivas Kandagatla if (!nvmem || nvmem->read_only || 127869aba794SSrinivas Kandagatla (cell->bit_offset == 0 && len != cell->bytes)) 127969aba794SSrinivas Kandagatla return -EINVAL; 128069aba794SSrinivas Kandagatla 128169aba794SSrinivas Kandagatla if (cell->bit_offset || cell->nbits) { 128269aba794SSrinivas Kandagatla buf = nvmem_cell_prepare_write_buffer(cell, buf, len); 128369aba794SSrinivas Kandagatla if (IS_ERR(buf)) 128469aba794SSrinivas Kandagatla return PTR_ERR(buf); 128569aba794SSrinivas Kandagatla } 128669aba794SSrinivas Kandagatla 1287795ddd18SSrinivas Kandagatla rc = nvmem_reg_write(nvmem, cell->offset, buf, cell->bytes); 128869aba794SSrinivas Kandagatla 128969aba794SSrinivas Kandagatla /* free the tmp buffer */ 1290ace22170SAxel Lin if (cell->bit_offset || cell->nbits) 129169aba794SSrinivas Kandagatla kfree(buf); 129269aba794SSrinivas Kandagatla 1293287980e4SArnd Bergmann if (rc) 129469aba794SSrinivas Kandagatla return rc; 129569aba794SSrinivas Kandagatla 129669aba794SSrinivas Kandagatla return len; 129769aba794SSrinivas Kandagatla } 129869aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_write); 129969aba794SSrinivas Kandagatla 1300e2a5402eSSrinivas Kandagatla /** 1301d026d70aSLeonard Crestez * nvmem_cell_read_u32() - Read a cell value as an u32 1302d026d70aSLeonard Crestez * 1303d026d70aSLeonard Crestez * @dev: Device that requests the nvmem cell. 1304d026d70aSLeonard Crestez * @cell_id: Name of nvmem cell to read. 1305d026d70aSLeonard Crestez * @val: pointer to output value. 1306d026d70aSLeonard Crestez * 1307d026d70aSLeonard Crestez * Return: 0 on success or negative errno. 1308d026d70aSLeonard Crestez */ 1309d026d70aSLeonard Crestez int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val) 1310d026d70aSLeonard Crestez { 1311d026d70aSLeonard Crestez struct nvmem_cell *cell; 1312d026d70aSLeonard Crestez void *buf; 1313d026d70aSLeonard Crestez size_t len; 1314d026d70aSLeonard Crestez 1315d026d70aSLeonard Crestez cell = nvmem_cell_get(dev, cell_id); 1316d026d70aSLeonard Crestez if (IS_ERR(cell)) 1317d026d70aSLeonard Crestez return PTR_ERR(cell); 1318d026d70aSLeonard Crestez 1319d026d70aSLeonard Crestez buf = nvmem_cell_read(cell, &len); 1320d026d70aSLeonard Crestez if (IS_ERR(buf)) { 1321d026d70aSLeonard Crestez nvmem_cell_put(cell); 1322d026d70aSLeonard Crestez return PTR_ERR(buf); 1323d026d70aSLeonard Crestez } 1324d026d70aSLeonard Crestez if (len != sizeof(*val)) { 1325d026d70aSLeonard Crestez kfree(buf); 1326d026d70aSLeonard Crestez nvmem_cell_put(cell); 1327d026d70aSLeonard Crestez return -EINVAL; 1328d026d70aSLeonard Crestez } 1329d026d70aSLeonard Crestez memcpy(val, buf, sizeof(*val)); 1330d026d70aSLeonard Crestez 1331d026d70aSLeonard Crestez kfree(buf); 1332d026d70aSLeonard Crestez nvmem_cell_put(cell); 1333d026d70aSLeonard Crestez return 0; 1334d026d70aSLeonard Crestez } 1335d026d70aSLeonard Crestez EXPORT_SYMBOL_GPL(nvmem_cell_read_u32); 1336d026d70aSLeonard Crestez 1337d026d70aSLeonard Crestez /** 1338e2a5402eSSrinivas Kandagatla * nvmem_device_cell_read() - Read a given nvmem device and cell 1339e2a5402eSSrinivas Kandagatla * 1340e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to read from. 1341e2a5402eSSrinivas Kandagatla * @info: nvmem cell info to be read. 1342e2a5402eSSrinivas Kandagatla * @buf: buffer pointer which will be populated on successful read. 1343e2a5402eSSrinivas Kandagatla * 1344e2a5402eSSrinivas Kandagatla * Return: length of successful bytes read on success and negative 1345e2a5402eSSrinivas Kandagatla * error code on error. 1346e2a5402eSSrinivas Kandagatla */ 1347e2a5402eSSrinivas Kandagatla ssize_t nvmem_device_cell_read(struct nvmem_device *nvmem, 1348e2a5402eSSrinivas Kandagatla struct nvmem_cell_info *info, void *buf) 1349e2a5402eSSrinivas Kandagatla { 1350e2a5402eSSrinivas Kandagatla struct nvmem_cell cell; 1351e2a5402eSSrinivas Kandagatla int rc; 1352e2a5402eSSrinivas Kandagatla ssize_t len; 1353e2a5402eSSrinivas Kandagatla 1354795ddd18SSrinivas Kandagatla if (!nvmem) 1355e2a5402eSSrinivas Kandagatla return -EINVAL; 1356e2a5402eSSrinivas Kandagatla 1357e2a5402eSSrinivas Kandagatla rc = nvmem_cell_info_to_nvmem_cell(nvmem, info, &cell); 1358287980e4SArnd Bergmann if (rc) 1359e2a5402eSSrinivas Kandagatla return rc; 1360e2a5402eSSrinivas Kandagatla 1361e2a5402eSSrinivas Kandagatla rc = __nvmem_cell_read(nvmem, &cell, buf, &len); 1362287980e4SArnd Bergmann if (rc) 1363e2a5402eSSrinivas Kandagatla return rc; 1364e2a5402eSSrinivas Kandagatla 1365e2a5402eSSrinivas Kandagatla return len; 1366e2a5402eSSrinivas Kandagatla } 1367e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_cell_read); 1368e2a5402eSSrinivas Kandagatla 1369e2a5402eSSrinivas Kandagatla /** 1370e2a5402eSSrinivas Kandagatla * nvmem_device_cell_write() - Write cell to a given nvmem device 1371e2a5402eSSrinivas Kandagatla * 1372e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to be written to. 137329143268SVivek Gautam * @info: nvmem cell info to be written. 1374e2a5402eSSrinivas Kandagatla * @buf: buffer to be written to cell. 1375e2a5402eSSrinivas Kandagatla * 1376e2a5402eSSrinivas Kandagatla * Return: length of bytes written or negative error code on failure. 1377e2a5402eSSrinivas Kandagatla * */ 1378e2a5402eSSrinivas Kandagatla int nvmem_device_cell_write(struct nvmem_device *nvmem, 1379e2a5402eSSrinivas Kandagatla struct nvmem_cell_info *info, void *buf) 1380e2a5402eSSrinivas Kandagatla { 1381e2a5402eSSrinivas Kandagatla struct nvmem_cell cell; 1382e2a5402eSSrinivas Kandagatla int rc; 1383e2a5402eSSrinivas Kandagatla 1384795ddd18SSrinivas Kandagatla if (!nvmem) 1385e2a5402eSSrinivas Kandagatla return -EINVAL; 1386e2a5402eSSrinivas Kandagatla 1387e2a5402eSSrinivas Kandagatla rc = nvmem_cell_info_to_nvmem_cell(nvmem, info, &cell); 1388287980e4SArnd Bergmann if (rc) 1389e2a5402eSSrinivas Kandagatla return rc; 1390e2a5402eSSrinivas Kandagatla 1391e2a5402eSSrinivas Kandagatla return nvmem_cell_write(&cell, buf, cell.bytes); 1392e2a5402eSSrinivas Kandagatla } 1393e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_cell_write); 1394e2a5402eSSrinivas Kandagatla 1395e2a5402eSSrinivas Kandagatla /** 1396e2a5402eSSrinivas Kandagatla * nvmem_device_read() - Read from a given nvmem device 1397e2a5402eSSrinivas Kandagatla * 1398e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to read from. 1399e2a5402eSSrinivas Kandagatla * @offset: offset in nvmem device. 1400e2a5402eSSrinivas Kandagatla * @bytes: number of bytes to read. 1401e2a5402eSSrinivas Kandagatla * @buf: buffer pointer which will be populated on successful read. 1402e2a5402eSSrinivas Kandagatla * 1403e2a5402eSSrinivas Kandagatla * Return: length of successful bytes read on success and negative 1404e2a5402eSSrinivas Kandagatla * error code on error. 1405e2a5402eSSrinivas Kandagatla */ 1406e2a5402eSSrinivas Kandagatla int nvmem_device_read(struct nvmem_device *nvmem, 1407e2a5402eSSrinivas Kandagatla unsigned int offset, 1408e2a5402eSSrinivas Kandagatla size_t bytes, void *buf) 1409e2a5402eSSrinivas Kandagatla { 1410e2a5402eSSrinivas Kandagatla int rc; 1411e2a5402eSSrinivas Kandagatla 1412795ddd18SSrinivas Kandagatla if (!nvmem) 1413e2a5402eSSrinivas Kandagatla return -EINVAL; 1414e2a5402eSSrinivas Kandagatla 1415795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, offset, buf, bytes); 1416e2a5402eSSrinivas Kandagatla 1417287980e4SArnd Bergmann if (rc) 1418e2a5402eSSrinivas Kandagatla return rc; 1419e2a5402eSSrinivas Kandagatla 1420e2a5402eSSrinivas Kandagatla return bytes; 1421e2a5402eSSrinivas Kandagatla } 1422e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_read); 1423e2a5402eSSrinivas Kandagatla 1424e2a5402eSSrinivas Kandagatla /** 1425e2a5402eSSrinivas Kandagatla * nvmem_device_write() - Write cell to a given nvmem device 1426e2a5402eSSrinivas Kandagatla * 1427e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to be written to. 1428e2a5402eSSrinivas Kandagatla * @offset: offset in nvmem device. 1429e2a5402eSSrinivas Kandagatla * @bytes: number of bytes to write. 1430e2a5402eSSrinivas Kandagatla * @buf: buffer to be written. 1431e2a5402eSSrinivas Kandagatla * 1432e2a5402eSSrinivas Kandagatla * Return: length of bytes written or negative error code on failure. 1433e2a5402eSSrinivas Kandagatla * */ 1434e2a5402eSSrinivas Kandagatla int nvmem_device_write(struct nvmem_device *nvmem, 1435e2a5402eSSrinivas Kandagatla unsigned int offset, 1436e2a5402eSSrinivas Kandagatla size_t bytes, void *buf) 1437e2a5402eSSrinivas Kandagatla { 1438e2a5402eSSrinivas Kandagatla int rc; 1439e2a5402eSSrinivas Kandagatla 1440795ddd18SSrinivas Kandagatla if (!nvmem) 1441e2a5402eSSrinivas Kandagatla return -EINVAL; 1442e2a5402eSSrinivas Kandagatla 1443795ddd18SSrinivas Kandagatla rc = nvmem_reg_write(nvmem, offset, buf, bytes); 1444e2a5402eSSrinivas Kandagatla 1445287980e4SArnd Bergmann if (rc) 1446e2a5402eSSrinivas Kandagatla return rc; 1447e2a5402eSSrinivas Kandagatla 1448e2a5402eSSrinivas Kandagatla 1449e2a5402eSSrinivas Kandagatla return bytes; 1450e2a5402eSSrinivas Kandagatla } 1451e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_write); 1452e2a5402eSSrinivas Kandagatla 1453d7b9fd16SBartosz Golaszewski /** 1454b985f4cbSBartosz Golaszewski * nvmem_add_cell_table() - register a table of cell info entries 1455b985f4cbSBartosz Golaszewski * 1456b985f4cbSBartosz Golaszewski * @table: table of cell info entries 1457b985f4cbSBartosz Golaszewski */ 1458b985f4cbSBartosz Golaszewski void nvmem_add_cell_table(struct nvmem_cell_table *table) 1459b985f4cbSBartosz Golaszewski { 1460b985f4cbSBartosz Golaszewski mutex_lock(&nvmem_cell_mutex); 1461b985f4cbSBartosz Golaszewski list_add_tail(&table->node, &nvmem_cell_tables); 1462b985f4cbSBartosz Golaszewski mutex_unlock(&nvmem_cell_mutex); 1463b985f4cbSBartosz Golaszewski } 1464b985f4cbSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_add_cell_table); 1465b985f4cbSBartosz Golaszewski 1466b985f4cbSBartosz Golaszewski /** 1467b985f4cbSBartosz Golaszewski * nvmem_del_cell_table() - remove a previously registered cell info table 1468b985f4cbSBartosz Golaszewski * 1469b985f4cbSBartosz Golaszewski * @table: table of cell info entries 1470b985f4cbSBartosz Golaszewski */ 1471b985f4cbSBartosz Golaszewski void nvmem_del_cell_table(struct nvmem_cell_table *table) 1472b985f4cbSBartosz Golaszewski { 1473b985f4cbSBartosz Golaszewski mutex_lock(&nvmem_cell_mutex); 1474b985f4cbSBartosz Golaszewski list_del(&table->node); 1475b985f4cbSBartosz Golaszewski mutex_unlock(&nvmem_cell_mutex); 1476b985f4cbSBartosz Golaszewski } 1477b985f4cbSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_del_cell_table); 1478b985f4cbSBartosz Golaszewski 1479b985f4cbSBartosz Golaszewski /** 1480506157beSBartosz Golaszewski * nvmem_add_cell_lookups() - register a list of cell lookup entries 1481506157beSBartosz Golaszewski * 1482506157beSBartosz Golaszewski * @entries: array of cell lookup entries 1483506157beSBartosz Golaszewski * @nentries: number of cell lookup entries in the array 1484506157beSBartosz Golaszewski */ 1485506157beSBartosz Golaszewski void nvmem_add_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries) 1486506157beSBartosz Golaszewski { 1487506157beSBartosz Golaszewski int i; 1488506157beSBartosz Golaszewski 1489506157beSBartosz Golaszewski mutex_lock(&nvmem_lookup_mutex); 1490506157beSBartosz Golaszewski for (i = 0; i < nentries; i++) 1491506157beSBartosz Golaszewski list_add_tail(&entries[i].node, &nvmem_lookup_list); 1492506157beSBartosz Golaszewski mutex_unlock(&nvmem_lookup_mutex); 1493506157beSBartosz Golaszewski } 1494506157beSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_add_cell_lookups); 1495506157beSBartosz Golaszewski 1496506157beSBartosz Golaszewski /** 1497506157beSBartosz Golaszewski * nvmem_del_cell_lookups() - remove a list of previously added cell lookup 1498506157beSBartosz Golaszewski * entries 1499506157beSBartosz Golaszewski * 1500506157beSBartosz Golaszewski * @entries: array of cell lookup entries 1501506157beSBartosz Golaszewski * @nentries: number of cell lookup entries in the array 1502506157beSBartosz Golaszewski */ 1503506157beSBartosz Golaszewski void nvmem_del_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries) 1504506157beSBartosz Golaszewski { 1505506157beSBartosz Golaszewski int i; 1506506157beSBartosz Golaszewski 1507506157beSBartosz Golaszewski mutex_lock(&nvmem_lookup_mutex); 1508506157beSBartosz Golaszewski for (i = 0; i < nentries; i++) 1509506157beSBartosz Golaszewski list_del(&entries[i].node); 1510506157beSBartosz Golaszewski mutex_unlock(&nvmem_lookup_mutex); 1511506157beSBartosz Golaszewski } 1512506157beSBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_del_cell_lookups); 1513506157beSBartosz Golaszewski 1514506157beSBartosz Golaszewski /** 1515d7b9fd16SBartosz Golaszewski * nvmem_dev_name() - Get the name of a given nvmem device. 1516d7b9fd16SBartosz Golaszewski * 1517d7b9fd16SBartosz Golaszewski * @nvmem: nvmem device. 1518d7b9fd16SBartosz Golaszewski * 1519d7b9fd16SBartosz Golaszewski * Return: name of the nvmem device. 1520d7b9fd16SBartosz Golaszewski */ 1521d7b9fd16SBartosz Golaszewski const char *nvmem_dev_name(struct nvmem_device *nvmem) 1522d7b9fd16SBartosz Golaszewski { 1523d7b9fd16SBartosz Golaszewski return dev_name(&nvmem->dev); 1524d7b9fd16SBartosz Golaszewski } 1525d7b9fd16SBartosz Golaszewski EXPORT_SYMBOL_GPL(nvmem_dev_name); 1526d7b9fd16SBartosz Golaszewski 1527eace75cfSSrinivas Kandagatla static int __init nvmem_init(void) 1528eace75cfSSrinivas Kandagatla { 1529eace75cfSSrinivas Kandagatla return bus_register(&nvmem_bus_type); 1530eace75cfSSrinivas Kandagatla } 1531eace75cfSSrinivas Kandagatla 1532eace75cfSSrinivas Kandagatla static void __exit nvmem_exit(void) 1533eace75cfSSrinivas Kandagatla { 1534eace75cfSSrinivas Kandagatla bus_unregister(&nvmem_bus_type); 1535eace75cfSSrinivas Kandagatla } 1536eace75cfSSrinivas Kandagatla 1537eace75cfSSrinivas Kandagatla subsys_initcall(nvmem_init); 1538eace75cfSSrinivas Kandagatla module_exit(nvmem_exit); 1539eace75cfSSrinivas Kandagatla 1540eace75cfSSrinivas Kandagatla MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org"); 1541eace75cfSSrinivas Kandagatla MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com"); 1542eace75cfSSrinivas Kandagatla MODULE_DESCRIPTION("nvmem Driver Core"); 1543eace75cfSSrinivas Kandagatla MODULE_LICENSE("GPL v2"); 1544