1eace75cfSSrinivas Kandagatla /* 2eace75cfSSrinivas Kandagatla * nvmem framework core. 3eace75cfSSrinivas Kandagatla * 4eace75cfSSrinivas Kandagatla * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org> 5eace75cfSSrinivas Kandagatla * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com> 6eace75cfSSrinivas Kandagatla * 7eace75cfSSrinivas Kandagatla * This program is free software; you can redistribute it and/or modify 8eace75cfSSrinivas Kandagatla * it under the terms of the GNU General Public License version 2 and 9eace75cfSSrinivas Kandagatla * only version 2 as published by the Free Software Foundation. 10eace75cfSSrinivas Kandagatla * 11eace75cfSSrinivas Kandagatla * This program is distributed in the hope that it will be useful, 12eace75cfSSrinivas Kandagatla * but WITHOUT ANY WARRANTY; without even the implied warranty of 13eace75cfSSrinivas Kandagatla * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14eace75cfSSrinivas Kandagatla * GNU General Public License for more details. 15eace75cfSSrinivas Kandagatla */ 16eace75cfSSrinivas Kandagatla 17eace75cfSSrinivas Kandagatla #include <linux/device.h> 18eace75cfSSrinivas Kandagatla #include <linux/export.h> 19eace75cfSSrinivas Kandagatla #include <linux/fs.h> 20eace75cfSSrinivas Kandagatla #include <linux/idr.h> 21eace75cfSSrinivas Kandagatla #include <linux/init.h> 22eace75cfSSrinivas Kandagatla #include <linux/module.h> 23eace75cfSSrinivas Kandagatla #include <linux/nvmem-consumer.h> 24eace75cfSSrinivas Kandagatla #include <linux/nvmem-provider.h> 25eace75cfSSrinivas Kandagatla #include <linux/of.h> 26eace75cfSSrinivas Kandagatla #include <linux/slab.h> 27eace75cfSSrinivas Kandagatla 28eace75cfSSrinivas Kandagatla struct nvmem_device { 29eace75cfSSrinivas Kandagatla const char *name; 30eace75cfSSrinivas Kandagatla struct module *owner; 31eace75cfSSrinivas Kandagatla struct device dev; 32eace75cfSSrinivas Kandagatla int stride; 33eace75cfSSrinivas Kandagatla int word_size; 34eace75cfSSrinivas Kandagatla int ncells; 35eace75cfSSrinivas Kandagatla int id; 36eace75cfSSrinivas Kandagatla int users; 37eace75cfSSrinivas Kandagatla size_t size; 38eace75cfSSrinivas Kandagatla bool read_only; 39b6c217abSAndrew Lunn int flags; 40b6c217abSAndrew Lunn struct bin_attribute eeprom; 41b6c217abSAndrew Lunn struct device *base_dev; 42795ddd18SSrinivas Kandagatla nvmem_reg_read_t reg_read; 43795ddd18SSrinivas Kandagatla nvmem_reg_write_t reg_write; 44795ddd18SSrinivas Kandagatla void *priv; 45eace75cfSSrinivas Kandagatla }; 46eace75cfSSrinivas Kandagatla 47b6c217abSAndrew Lunn #define FLAG_COMPAT BIT(0) 48b6c217abSAndrew Lunn 49eace75cfSSrinivas Kandagatla struct nvmem_cell { 50eace75cfSSrinivas Kandagatla const char *name; 51eace75cfSSrinivas Kandagatla int offset; 52eace75cfSSrinivas Kandagatla int bytes; 53eace75cfSSrinivas Kandagatla int bit_offset; 54eace75cfSSrinivas Kandagatla int nbits; 55eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem; 56eace75cfSSrinivas Kandagatla struct list_head node; 57eace75cfSSrinivas Kandagatla }; 58eace75cfSSrinivas Kandagatla 59eace75cfSSrinivas Kandagatla static DEFINE_MUTEX(nvmem_mutex); 60eace75cfSSrinivas Kandagatla static DEFINE_IDA(nvmem_ida); 61eace75cfSSrinivas Kandagatla 62eace75cfSSrinivas Kandagatla static LIST_HEAD(nvmem_cells); 63eace75cfSSrinivas Kandagatla static DEFINE_MUTEX(nvmem_cells_mutex); 64eace75cfSSrinivas Kandagatla 65b6c217abSAndrew Lunn #ifdef CONFIG_DEBUG_LOCK_ALLOC 66b6c217abSAndrew Lunn static struct lock_class_key eeprom_lock_key; 67b6c217abSAndrew Lunn #endif 68b6c217abSAndrew Lunn 69eace75cfSSrinivas Kandagatla #define to_nvmem_device(d) container_of(d, struct nvmem_device, dev) 70795ddd18SSrinivas Kandagatla static int nvmem_reg_read(struct nvmem_device *nvmem, unsigned int offset, 71795ddd18SSrinivas Kandagatla void *val, size_t bytes) 72795ddd18SSrinivas Kandagatla { 73795ddd18SSrinivas Kandagatla if (nvmem->reg_read) 74795ddd18SSrinivas Kandagatla return nvmem->reg_read(nvmem->priv, offset, val, bytes); 75795ddd18SSrinivas Kandagatla 76795ddd18SSrinivas Kandagatla return -EINVAL; 77795ddd18SSrinivas Kandagatla } 78795ddd18SSrinivas Kandagatla 79795ddd18SSrinivas Kandagatla static int nvmem_reg_write(struct nvmem_device *nvmem, unsigned int offset, 80795ddd18SSrinivas Kandagatla void *val, size_t bytes) 81795ddd18SSrinivas Kandagatla { 82795ddd18SSrinivas Kandagatla if (nvmem->reg_write) 83795ddd18SSrinivas Kandagatla return nvmem->reg_write(nvmem->priv, offset, val, bytes); 84795ddd18SSrinivas Kandagatla 85795ddd18SSrinivas Kandagatla return -EINVAL; 86795ddd18SSrinivas Kandagatla } 87eace75cfSSrinivas Kandagatla 88eace75cfSSrinivas Kandagatla static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj, 89eace75cfSSrinivas Kandagatla struct bin_attribute *attr, 90eace75cfSSrinivas Kandagatla char *buf, loff_t pos, size_t count) 91eace75cfSSrinivas Kandagatla { 92b6c217abSAndrew Lunn struct device *dev; 93b6c217abSAndrew Lunn struct nvmem_device *nvmem; 94eace75cfSSrinivas Kandagatla int rc; 95eace75cfSSrinivas Kandagatla 96b6c217abSAndrew Lunn if (attr->private) 97b6c217abSAndrew Lunn dev = attr->private; 98b6c217abSAndrew Lunn else 99b6c217abSAndrew Lunn dev = container_of(kobj, struct device, kobj); 100b6c217abSAndrew Lunn nvmem = to_nvmem_device(dev); 101b6c217abSAndrew Lunn 102eace75cfSSrinivas Kandagatla /* Stop the user from reading */ 1037c806883SZhengShunQian if (pos >= nvmem->size) 104eace75cfSSrinivas Kandagatla return 0; 105eace75cfSSrinivas Kandagatla 106313a72ffSSrinivas Kandagatla if (count < nvmem->word_size) 107313a72ffSSrinivas Kandagatla return -EINVAL; 108313a72ffSSrinivas Kandagatla 109eace75cfSSrinivas Kandagatla if (pos + count > nvmem->size) 110eace75cfSSrinivas Kandagatla count = nvmem->size - pos; 111eace75cfSSrinivas Kandagatla 112eace75cfSSrinivas Kandagatla count = round_down(count, nvmem->word_size); 113eace75cfSSrinivas Kandagatla 114795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, pos, buf, count); 115eace75cfSSrinivas Kandagatla 116287980e4SArnd Bergmann if (rc) 117eace75cfSSrinivas Kandagatla return rc; 118eace75cfSSrinivas Kandagatla 119eace75cfSSrinivas Kandagatla return count; 120eace75cfSSrinivas Kandagatla } 121eace75cfSSrinivas Kandagatla 122eace75cfSSrinivas Kandagatla static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj, 123eace75cfSSrinivas Kandagatla struct bin_attribute *attr, 124eace75cfSSrinivas Kandagatla char *buf, loff_t pos, size_t count) 125eace75cfSSrinivas Kandagatla { 126b6c217abSAndrew Lunn struct device *dev; 127b6c217abSAndrew Lunn struct nvmem_device *nvmem; 128eace75cfSSrinivas Kandagatla int rc; 129eace75cfSSrinivas Kandagatla 130b6c217abSAndrew Lunn if (attr->private) 131b6c217abSAndrew Lunn dev = attr->private; 132b6c217abSAndrew Lunn else 133b6c217abSAndrew Lunn dev = container_of(kobj, struct device, kobj); 134b6c217abSAndrew Lunn nvmem = to_nvmem_device(dev); 135b6c217abSAndrew Lunn 136eace75cfSSrinivas Kandagatla /* Stop the user from writing */ 1377c806883SZhengShunQian if (pos >= nvmem->size) 138eace75cfSSrinivas Kandagatla return 0; 139eace75cfSSrinivas Kandagatla 140313a72ffSSrinivas Kandagatla if (count < nvmem->word_size) 141313a72ffSSrinivas Kandagatla return -EINVAL; 142313a72ffSSrinivas Kandagatla 143eace75cfSSrinivas Kandagatla if (pos + count > nvmem->size) 144eace75cfSSrinivas Kandagatla count = nvmem->size - pos; 145eace75cfSSrinivas Kandagatla 146eace75cfSSrinivas Kandagatla count = round_down(count, nvmem->word_size); 147eace75cfSSrinivas Kandagatla 148795ddd18SSrinivas Kandagatla rc = nvmem_reg_write(nvmem, pos, buf, count); 149eace75cfSSrinivas Kandagatla 150287980e4SArnd Bergmann if (rc) 151eace75cfSSrinivas Kandagatla return rc; 152eace75cfSSrinivas Kandagatla 153eace75cfSSrinivas Kandagatla return count; 154eace75cfSSrinivas Kandagatla } 155eace75cfSSrinivas Kandagatla 156eace75cfSSrinivas Kandagatla /* default read/write permissions */ 157eace75cfSSrinivas Kandagatla static struct bin_attribute bin_attr_rw_nvmem = { 158eace75cfSSrinivas Kandagatla .attr = { 159eace75cfSSrinivas Kandagatla .name = "nvmem", 160eace75cfSSrinivas Kandagatla .mode = S_IWUSR | S_IRUGO, 161eace75cfSSrinivas Kandagatla }, 162eace75cfSSrinivas Kandagatla .read = bin_attr_nvmem_read, 163eace75cfSSrinivas Kandagatla .write = bin_attr_nvmem_write, 164eace75cfSSrinivas Kandagatla }; 165eace75cfSSrinivas Kandagatla 166eace75cfSSrinivas Kandagatla static struct bin_attribute *nvmem_bin_rw_attributes[] = { 167eace75cfSSrinivas Kandagatla &bin_attr_rw_nvmem, 168eace75cfSSrinivas Kandagatla NULL, 169eace75cfSSrinivas Kandagatla }; 170eace75cfSSrinivas Kandagatla 171eace75cfSSrinivas Kandagatla static const struct attribute_group nvmem_bin_rw_group = { 172eace75cfSSrinivas Kandagatla .bin_attrs = nvmem_bin_rw_attributes, 173eace75cfSSrinivas Kandagatla }; 174eace75cfSSrinivas Kandagatla 175eace75cfSSrinivas Kandagatla static const struct attribute_group *nvmem_rw_dev_groups[] = { 176eace75cfSSrinivas Kandagatla &nvmem_bin_rw_group, 177eace75cfSSrinivas Kandagatla NULL, 178eace75cfSSrinivas Kandagatla }; 179eace75cfSSrinivas Kandagatla 180eace75cfSSrinivas Kandagatla /* read only permission */ 181eace75cfSSrinivas Kandagatla static struct bin_attribute bin_attr_ro_nvmem = { 182eace75cfSSrinivas Kandagatla .attr = { 183eace75cfSSrinivas Kandagatla .name = "nvmem", 184eace75cfSSrinivas Kandagatla .mode = S_IRUGO, 185eace75cfSSrinivas Kandagatla }, 186eace75cfSSrinivas Kandagatla .read = bin_attr_nvmem_read, 187eace75cfSSrinivas Kandagatla }; 188eace75cfSSrinivas Kandagatla 189eace75cfSSrinivas Kandagatla static struct bin_attribute *nvmem_bin_ro_attributes[] = { 190eace75cfSSrinivas Kandagatla &bin_attr_ro_nvmem, 191eace75cfSSrinivas Kandagatla NULL, 192eace75cfSSrinivas Kandagatla }; 193eace75cfSSrinivas Kandagatla 194eace75cfSSrinivas Kandagatla static const struct attribute_group nvmem_bin_ro_group = { 195eace75cfSSrinivas Kandagatla .bin_attrs = nvmem_bin_ro_attributes, 196eace75cfSSrinivas Kandagatla }; 197eace75cfSSrinivas Kandagatla 198eace75cfSSrinivas Kandagatla static const struct attribute_group *nvmem_ro_dev_groups[] = { 199eace75cfSSrinivas Kandagatla &nvmem_bin_ro_group, 200eace75cfSSrinivas Kandagatla NULL, 201eace75cfSSrinivas Kandagatla }; 202eace75cfSSrinivas Kandagatla 203811b0d65SAndrew Lunn /* default read/write permissions, root only */ 204811b0d65SAndrew Lunn static struct bin_attribute bin_attr_rw_root_nvmem = { 205811b0d65SAndrew Lunn .attr = { 206811b0d65SAndrew Lunn .name = "nvmem", 207811b0d65SAndrew Lunn .mode = S_IWUSR | S_IRUSR, 208811b0d65SAndrew Lunn }, 209811b0d65SAndrew Lunn .read = bin_attr_nvmem_read, 210811b0d65SAndrew Lunn .write = bin_attr_nvmem_write, 211811b0d65SAndrew Lunn }; 212811b0d65SAndrew Lunn 213811b0d65SAndrew Lunn static struct bin_attribute *nvmem_bin_rw_root_attributes[] = { 214811b0d65SAndrew Lunn &bin_attr_rw_root_nvmem, 215811b0d65SAndrew Lunn NULL, 216811b0d65SAndrew Lunn }; 217811b0d65SAndrew Lunn 218811b0d65SAndrew Lunn static const struct attribute_group nvmem_bin_rw_root_group = { 219811b0d65SAndrew Lunn .bin_attrs = nvmem_bin_rw_root_attributes, 220811b0d65SAndrew Lunn }; 221811b0d65SAndrew Lunn 222811b0d65SAndrew Lunn static const struct attribute_group *nvmem_rw_root_dev_groups[] = { 223811b0d65SAndrew Lunn &nvmem_bin_rw_root_group, 224811b0d65SAndrew Lunn NULL, 225811b0d65SAndrew Lunn }; 226811b0d65SAndrew Lunn 227811b0d65SAndrew Lunn /* read only permission, root only */ 228811b0d65SAndrew Lunn static struct bin_attribute bin_attr_ro_root_nvmem = { 229811b0d65SAndrew Lunn .attr = { 230811b0d65SAndrew Lunn .name = "nvmem", 231811b0d65SAndrew Lunn .mode = S_IRUSR, 232811b0d65SAndrew Lunn }, 233811b0d65SAndrew Lunn .read = bin_attr_nvmem_read, 234811b0d65SAndrew Lunn }; 235811b0d65SAndrew Lunn 236811b0d65SAndrew Lunn static struct bin_attribute *nvmem_bin_ro_root_attributes[] = { 237811b0d65SAndrew Lunn &bin_attr_ro_root_nvmem, 238811b0d65SAndrew Lunn NULL, 239811b0d65SAndrew Lunn }; 240811b0d65SAndrew Lunn 241811b0d65SAndrew Lunn static const struct attribute_group nvmem_bin_ro_root_group = { 242811b0d65SAndrew Lunn .bin_attrs = nvmem_bin_ro_root_attributes, 243811b0d65SAndrew Lunn }; 244811b0d65SAndrew Lunn 245811b0d65SAndrew Lunn static const struct attribute_group *nvmem_ro_root_dev_groups[] = { 246811b0d65SAndrew Lunn &nvmem_bin_ro_root_group, 247811b0d65SAndrew Lunn NULL, 248811b0d65SAndrew Lunn }; 249811b0d65SAndrew Lunn 250eace75cfSSrinivas Kandagatla static void nvmem_release(struct device *dev) 251eace75cfSSrinivas Kandagatla { 252eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem = to_nvmem_device(dev); 253eace75cfSSrinivas Kandagatla 254eace75cfSSrinivas Kandagatla ida_simple_remove(&nvmem_ida, nvmem->id); 255eace75cfSSrinivas Kandagatla kfree(nvmem); 256eace75cfSSrinivas Kandagatla } 257eace75cfSSrinivas Kandagatla 258eace75cfSSrinivas Kandagatla static const struct device_type nvmem_provider_type = { 259eace75cfSSrinivas Kandagatla .release = nvmem_release, 260eace75cfSSrinivas Kandagatla }; 261eace75cfSSrinivas Kandagatla 262eace75cfSSrinivas Kandagatla static struct bus_type nvmem_bus_type = { 263eace75cfSSrinivas Kandagatla .name = "nvmem", 264eace75cfSSrinivas Kandagatla }; 265eace75cfSSrinivas Kandagatla 266eace75cfSSrinivas Kandagatla static int of_nvmem_match(struct device *dev, void *nvmem_np) 267eace75cfSSrinivas Kandagatla { 268eace75cfSSrinivas Kandagatla return dev->of_node == nvmem_np; 269eace75cfSSrinivas Kandagatla } 270eace75cfSSrinivas Kandagatla 271eace75cfSSrinivas Kandagatla static struct nvmem_device *of_nvmem_find(struct device_node *nvmem_np) 272eace75cfSSrinivas Kandagatla { 273eace75cfSSrinivas Kandagatla struct device *d; 274eace75cfSSrinivas Kandagatla 275eace75cfSSrinivas Kandagatla if (!nvmem_np) 276eace75cfSSrinivas Kandagatla return NULL; 277eace75cfSSrinivas Kandagatla 278eace75cfSSrinivas Kandagatla d = bus_find_device(&nvmem_bus_type, NULL, nvmem_np, of_nvmem_match); 279eace75cfSSrinivas Kandagatla 280eace75cfSSrinivas Kandagatla if (!d) 281eace75cfSSrinivas Kandagatla return NULL; 282eace75cfSSrinivas Kandagatla 283eace75cfSSrinivas Kandagatla return to_nvmem_device(d); 284eace75cfSSrinivas Kandagatla } 285eace75cfSSrinivas Kandagatla 286eace75cfSSrinivas Kandagatla static struct nvmem_cell *nvmem_find_cell(const char *cell_id) 287eace75cfSSrinivas Kandagatla { 288eace75cfSSrinivas Kandagatla struct nvmem_cell *p; 289eace75cfSSrinivas Kandagatla 290eace75cfSSrinivas Kandagatla list_for_each_entry(p, &nvmem_cells, node) 291eace75cfSSrinivas Kandagatla if (p && !strcmp(p->name, cell_id)) 292eace75cfSSrinivas Kandagatla return p; 293eace75cfSSrinivas Kandagatla 294eace75cfSSrinivas Kandagatla return NULL; 295eace75cfSSrinivas Kandagatla } 296eace75cfSSrinivas Kandagatla 297eace75cfSSrinivas Kandagatla static void nvmem_cell_drop(struct nvmem_cell *cell) 298eace75cfSSrinivas Kandagatla { 299eace75cfSSrinivas Kandagatla mutex_lock(&nvmem_cells_mutex); 300eace75cfSSrinivas Kandagatla list_del(&cell->node); 301eace75cfSSrinivas Kandagatla mutex_unlock(&nvmem_cells_mutex); 302eace75cfSSrinivas Kandagatla kfree(cell); 303eace75cfSSrinivas Kandagatla } 304eace75cfSSrinivas Kandagatla 305eace75cfSSrinivas Kandagatla static void nvmem_device_remove_all_cells(const struct nvmem_device *nvmem) 306eace75cfSSrinivas Kandagatla { 307eace75cfSSrinivas Kandagatla struct nvmem_cell *cell; 308eace75cfSSrinivas Kandagatla struct list_head *p, *n; 309eace75cfSSrinivas Kandagatla 310eace75cfSSrinivas Kandagatla list_for_each_safe(p, n, &nvmem_cells) { 311eace75cfSSrinivas Kandagatla cell = list_entry(p, struct nvmem_cell, node); 312eace75cfSSrinivas Kandagatla if (cell->nvmem == nvmem) 313eace75cfSSrinivas Kandagatla nvmem_cell_drop(cell); 314eace75cfSSrinivas Kandagatla } 315eace75cfSSrinivas Kandagatla } 316eace75cfSSrinivas Kandagatla 317eace75cfSSrinivas Kandagatla static void nvmem_cell_add(struct nvmem_cell *cell) 318eace75cfSSrinivas Kandagatla { 319eace75cfSSrinivas Kandagatla mutex_lock(&nvmem_cells_mutex); 320eace75cfSSrinivas Kandagatla list_add_tail(&cell->node, &nvmem_cells); 321eace75cfSSrinivas Kandagatla mutex_unlock(&nvmem_cells_mutex); 322eace75cfSSrinivas Kandagatla } 323eace75cfSSrinivas Kandagatla 324eace75cfSSrinivas Kandagatla static int nvmem_cell_info_to_nvmem_cell(struct nvmem_device *nvmem, 325eace75cfSSrinivas Kandagatla const struct nvmem_cell_info *info, 326eace75cfSSrinivas Kandagatla struct nvmem_cell *cell) 327eace75cfSSrinivas Kandagatla { 328eace75cfSSrinivas Kandagatla cell->nvmem = nvmem; 329eace75cfSSrinivas Kandagatla cell->offset = info->offset; 330eace75cfSSrinivas Kandagatla cell->bytes = info->bytes; 331eace75cfSSrinivas Kandagatla cell->name = info->name; 332eace75cfSSrinivas Kandagatla 333eace75cfSSrinivas Kandagatla cell->bit_offset = info->bit_offset; 334eace75cfSSrinivas Kandagatla cell->nbits = info->nbits; 335eace75cfSSrinivas Kandagatla 336eace75cfSSrinivas Kandagatla if (cell->nbits) 337eace75cfSSrinivas Kandagatla cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset, 338eace75cfSSrinivas Kandagatla BITS_PER_BYTE); 339eace75cfSSrinivas Kandagatla 340eace75cfSSrinivas Kandagatla if (!IS_ALIGNED(cell->offset, nvmem->stride)) { 341eace75cfSSrinivas Kandagatla dev_err(&nvmem->dev, 342eace75cfSSrinivas Kandagatla "cell %s unaligned to nvmem stride %d\n", 343eace75cfSSrinivas Kandagatla cell->name, nvmem->stride); 344eace75cfSSrinivas Kandagatla return -EINVAL; 345eace75cfSSrinivas Kandagatla } 346eace75cfSSrinivas Kandagatla 347eace75cfSSrinivas Kandagatla return 0; 348eace75cfSSrinivas Kandagatla } 349eace75cfSSrinivas Kandagatla 350eace75cfSSrinivas Kandagatla static int nvmem_add_cells(struct nvmem_device *nvmem, 351eace75cfSSrinivas Kandagatla const struct nvmem_config *cfg) 352eace75cfSSrinivas Kandagatla { 353eace75cfSSrinivas Kandagatla struct nvmem_cell **cells; 354eace75cfSSrinivas Kandagatla const struct nvmem_cell_info *info = cfg->cells; 355eace75cfSSrinivas Kandagatla int i, rval; 356eace75cfSSrinivas Kandagatla 357eace75cfSSrinivas Kandagatla cells = kcalloc(cfg->ncells, sizeof(*cells), GFP_KERNEL); 358eace75cfSSrinivas Kandagatla if (!cells) 359eace75cfSSrinivas Kandagatla return -ENOMEM; 360eace75cfSSrinivas Kandagatla 361eace75cfSSrinivas Kandagatla for (i = 0; i < cfg->ncells; i++) { 362eace75cfSSrinivas Kandagatla cells[i] = kzalloc(sizeof(**cells), GFP_KERNEL); 363eace75cfSSrinivas Kandagatla if (!cells[i]) { 364eace75cfSSrinivas Kandagatla rval = -ENOMEM; 365eace75cfSSrinivas Kandagatla goto err; 366eace75cfSSrinivas Kandagatla } 367eace75cfSSrinivas Kandagatla 368eace75cfSSrinivas Kandagatla rval = nvmem_cell_info_to_nvmem_cell(nvmem, &info[i], cells[i]); 369287980e4SArnd Bergmann if (rval) { 370eace75cfSSrinivas Kandagatla kfree(cells[i]); 371eace75cfSSrinivas Kandagatla goto err; 372eace75cfSSrinivas Kandagatla } 373eace75cfSSrinivas Kandagatla 374eace75cfSSrinivas Kandagatla nvmem_cell_add(cells[i]); 375eace75cfSSrinivas Kandagatla } 376eace75cfSSrinivas Kandagatla 377eace75cfSSrinivas Kandagatla nvmem->ncells = cfg->ncells; 378eace75cfSSrinivas Kandagatla /* remove tmp array */ 379eace75cfSSrinivas Kandagatla kfree(cells); 380eace75cfSSrinivas Kandagatla 381eace75cfSSrinivas Kandagatla return 0; 382eace75cfSSrinivas Kandagatla err: 383dfdf1414SRasmus Villemoes while (i--) 384eace75cfSSrinivas Kandagatla nvmem_cell_drop(cells[i]); 385eace75cfSSrinivas Kandagatla 386dfdf1414SRasmus Villemoes kfree(cells); 387dfdf1414SRasmus Villemoes 388eace75cfSSrinivas Kandagatla return rval; 389eace75cfSSrinivas Kandagatla } 390eace75cfSSrinivas Kandagatla 391b6c217abSAndrew Lunn /* 392b6c217abSAndrew Lunn * nvmem_setup_compat() - Create an additional binary entry in 393b6c217abSAndrew Lunn * drivers sys directory, to be backwards compatible with the older 394b6c217abSAndrew Lunn * drivers/misc/eeprom drivers. 395b6c217abSAndrew Lunn */ 396b6c217abSAndrew Lunn static int nvmem_setup_compat(struct nvmem_device *nvmem, 397b6c217abSAndrew Lunn const struct nvmem_config *config) 398b6c217abSAndrew Lunn { 399b6c217abSAndrew Lunn int rval; 400b6c217abSAndrew Lunn 401b6c217abSAndrew Lunn if (!config->base_dev) 402b6c217abSAndrew Lunn return -EINVAL; 403b6c217abSAndrew Lunn 404b6c217abSAndrew Lunn if (nvmem->read_only) 405b6c217abSAndrew Lunn nvmem->eeprom = bin_attr_ro_root_nvmem; 406b6c217abSAndrew Lunn else 407b6c217abSAndrew Lunn nvmem->eeprom = bin_attr_rw_root_nvmem; 408b6c217abSAndrew Lunn nvmem->eeprom.attr.name = "eeprom"; 409b6c217abSAndrew Lunn nvmem->eeprom.size = nvmem->size; 410b6c217abSAndrew Lunn #ifdef CONFIG_DEBUG_LOCK_ALLOC 411b6c217abSAndrew Lunn nvmem->eeprom.attr.key = &eeprom_lock_key; 412b6c217abSAndrew Lunn #endif 413b6c217abSAndrew Lunn nvmem->eeprom.private = &nvmem->dev; 414b6c217abSAndrew Lunn nvmem->base_dev = config->base_dev; 415b6c217abSAndrew Lunn 416b6c217abSAndrew Lunn rval = device_create_bin_file(nvmem->base_dev, &nvmem->eeprom); 417b6c217abSAndrew Lunn if (rval) { 418b6c217abSAndrew Lunn dev_err(&nvmem->dev, 419b6c217abSAndrew Lunn "Failed to create eeprom binary file %d\n", rval); 420b6c217abSAndrew Lunn return rval; 421b6c217abSAndrew Lunn } 422b6c217abSAndrew Lunn 423b6c217abSAndrew Lunn nvmem->flags |= FLAG_COMPAT; 424b6c217abSAndrew Lunn 425b6c217abSAndrew Lunn return 0; 426b6c217abSAndrew Lunn } 427b6c217abSAndrew Lunn 428eace75cfSSrinivas Kandagatla /** 429eace75cfSSrinivas Kandagatla * nvmem_register() - Register a nvmem device for given nvmem_config. 430eace75cfSSrinivas Kandagatla * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem 431eace75cfSSrinivas Kandagatla * 432eace75cfSSrinivas Kandagatla * @config: nvmem device configuration with which nvmem device is created. 433eace75cfSSrinivas Kandagatla * 434eace75cfSSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device 435eace75cfSSrinivas Kandagatla * on success. 436eace75cfSSrinivas Kandagatla */ 437eace75cfSSrinivas Kandagatla 438eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem_register(const struct nvmem_config *config) 439eace75cfSSrinivas Kandagatla { 440eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem; 441eace75cfSSrinivas Kandagatla struct device_node *np; 442eace75cfSSrinivas Kandagatla int rval; 443eace75cfSSrinivas Kandagatla 444eace75cfSSrinivas Kandagatla if (!config->dev) 445eace75cfSSrinivas Kandagatla return ERR_PTR(-EINVAL); 446eace75cfSSrinivas Kandagatla 447eace75cfSSrinivas Kandagatla nvmem = kzalloc(sizeof(*nvmem), GFP_KERNEL); 448eace75cfSSrinivas Kandagatla if (!nvmem) 449eace75cfSSrinivas Kandagatla return ERR_PTR(-ENOMEM); 450eace75cfSSrinivas Kandagatla 451eace75cfSSrinivas Kandagatla rval = ida_simple_get(&nvmem_ida, 0, 0, GFP_KERNEL); 452eace75cfSSrinivas Kandagatla if (rval < 0) { 453eace75cfSSrinivas Kandagatla kfree(nvmem); 454eace75cfSSrinivas Kandagatla return ERR_PTR(rval); 455eace75cfSSrinivas Kandagatla } 456eace75cfSSrinivas Kandagatla 457eace75cfSSrinivas Kandagatla nvmem->id = rval; 458eace75cfSSrinivas Kandagatla nvmem->owner = config->owner; 459795ddd18SSrinivas Kandagatla nvmem->stride = config->stride; 460795ddd18SSrinivas Kandagatla nvmem->word_size = config->word_size; 461795ddd18SSrinivas Kandagatla nvmem->size = config->size; 462eace75cfSSrinivas Kandagatla nvmem->dev.type = &nvmem_provider_type; 463eace75cfSSrinivas Kandagatla nvmem->dev.bus = &nvmem_bus_type; 464eace75cfSSrinivas Kandagatla nvmem->dev.parent = config->dev; 465795ddd18SSrinivas Kandagatla nvmem->priv = config->priv; 466795ddd18SSrinivas Kandagatla nvmem->reg_read = config->reg_read; 467795ddd18SSrinivas Kandagatla nvmem->reg_write = config->reg_write; 468eace75cfSSrinivas Kandagatla np = config->dev->of_node; 469eace75cfSSrinivas Kandagatla nvmem->dev.of_node = np; 470eace75cfSSrinivas Kandagatla dev_set_name(&nvmem->dev, "%s%d", 471eace75cfSSrinivas Kandagatla config->name ? : "nvmem", config->id); 472eace75cfSSrinivas Kandagatla 473eace75cfSSrinivas Kandagatla nvmem->read_only = of_property_read_bool(np, "read-only") | 474eace75cfSSrinivas Kandagatla config->read_only; 475eace75cfSSrinivas Kandagatla 476811b0d65SAndrew Lunn if (config->root_only) 477811b0d65SAndrew Lunn nvmem->dev.groups = nvmem->read_only ? 478811b0d65SAndrew Lunn nvmem_ro_root_dev_groups : 479811b0d65SAndrew Lunn nvmem_rw_root_dev_groups; 480811b0d65SAndrew Lunn else 481811b0d65SAndrew Lunn nvmem->dev.groups = nvmem->read_only ? 482811b0d65SAndrew Lunn nvmem_ro_dev_groups : 483eace75cfSSrinivas Kandagatla nvmem_rw_dev_groups; 484eace75cfSSrinivas Kandagatla 485eace75cfSSrinivas Kandagatla device_initialize(&nvmem->dev); 486eace75cfSSrinivas Kandagatla 487eace75cfSSrinivas Kandagatla dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name); 488eace75cfSSrinivas Kandagatla 489eace75cfSSrinivas Kandagatla rval = device_add(&nvmem->dev); 490b6c217abSAndrew Lunn if (rval) 491b6c217abSAndrew Lunn goto out; 492b6c217abSAndrew Lunn 493b6c217abSAndrew Lunn if (config->compat) { 494b6c217abSAndrew Lunn rval = nvmem_setup_compat(nvmem, config); 495b6c217abSAndrew Lunn if (rval) 496b6c217abSAndrew Lunn goto out; 497eace75cfSSrinivas Kandagatla } 498eace75cfSSrinivas Kandagatla 499eace75cfSSrinivas Kandagatla if (config->cells) 500eace75cfSSrinivas Kandagatla nvmem_add_cells(nvmem, config); 501eace75cfSSrinivas Kandagatla 502eace75cfSSrinivas Kandagatla return nvmem; 503b6c217abSAndrew Lunn out: 504b6c217abSAndrew Lunn ida_simple_remove(&nvmem_ida, nvmem->id); 505b6c217abSAndrew Lunn kfree(nvmem); 506b6c217abSAndrew Lunn return ERR_PTR(rval); 507eace75cfSSrinivas Kandagatla } 508eace75cfSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_register); 509eace75cfSSrinivas Kandagatla 510eace75cfSSrinivas Kandagatla /** 511eace75cfSSrinivas Kandagatla * nvmem_unregister() - Unregister previously registered nvmem device 512eace75cfSSrinivas Kandagatla * 513eace75cfSSrinivas Kandagatla * @nvmem: Pointer to previously registered nvmem device. 514eace75cfSSrinivas Kandagatla * 515eace75cfSSrinivas Kandagatla * Return: Will be an negative on error or a zero on success. 516eace75cfSSrinivas Kandagatla */ 517eace75cfSSrinivas Kandagatla int nvmem_unregister(struct nvmem_device *nvmem) 518eace75cfSSrinivas Kandagatla { 51969aba794SSrinivas Kandagatla mutex_lock(&nvmem_mutex); 52069aba794SSrinivas Kandagatla if (nvmem->users) { 52169aba794SSrinivas Kandagatla mutex_unlock(&nvmem_mutex); 522eace75cfSSrinivas Kandagatla return -EBUSY; 52369aba794SSrinivas Kandagatla } 52469aba794SSrinivas Kandagatla mutex_unlock(&nvmem_mutex); 525eace75cfSSrinivas Kandagatla 526b6c217abSAndrew Lunn if (nvmem->flags & FLAG_COMPAT) 527b6c217abSAndrew Lunn device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); 528b6c217abSAndrew Lunn 529eace75cfSSrinivas Kandagatla nvmem_device_remove_all_cells(nvmem); 530eace75cfSSrinivas Kandagatla device_del(&nvmem->dev); 531eace75cfSSrinivas Kandagatla 532eace75cfSSrinivas Kandagatla return 0; 533eace75cfSSrinivas Kandagatla } 534eace75cfSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_unregister); 535eace75cfSSrinivas Kandagatla 53669aba794SSrinivas Kandagatla static struct nvmem_device *__nvmem_device_get(struct device_node *np, 53769aba794SSrinivas Kandagatla struct nvmem_cell **cellp, 53869aba794SSrinivas Kandagatla const char *cell_id) 53969aba794SSrinivas Kandagatla { 54069aba794SSrinivas Kandagatla struct nvmem_device *nvmem = NULL; 54169aba794SSrinivas Kandagatla 54269aba794SSrinivas Kandagatla mutex_lock(&nvmem_mutex); 54369aba794SSrinivas Kandagatla 54469aba794SSrinivas Kandagatla if (np) { 54569aba794SSrinivas Kandagatla nvmem = of_nvmem_find(np); 54669aba794SSrinivas Kandagatla if (!nvmem) { 54769aba794SSrinivas Kandagatla mutex_unlock(&nvmem_mutex); 54869aba794SSrinivas Kandagatla return ERR_PTR(-EPROBE_DEFER); 54969aba794SSrinivas Kandagatla } 55069aba794SSrinivas Kandagatla } else { 55169aba794SSrinivas Kandagatla struct nvmem_cell *cell = nvmem_find_cell(cell_id); 55269aba794SSrinivas Kandagatla 55369aba794SSrinivas Kandagatla if (cell) { 55469aba794SSrinivas Kandagatla nvmem = cell->nvmem; 55569aba794SSrinivas Kandagatla *cellp = cell; 55669aba794SSrinivas Kandagatla } 55769aba794SSrinivas Kandagatla 55869aba794SSrinivas Kandagatla if (!nvmem) { 55969aba794SSrinivas Kandagatla mutex_unlock(&nvmem_mutex); 56069aba794SSrinivas Kandagatla return ERR_PTR(-ENOENT); 56169aba794SSrinivas Kandagatla } 56269aba794SSrinivas Kandagatla } 56369aba794SSrinivas Kandagatla 56469aba794SSrinivas Kandagatla nvmem->users++; 56569aba794SSrinivas Kandagatla mutex_unlock(&nvmem_mutex); 56669aba794SSrinivas Kandagatla 56769aba794SSrinivas Kandagatla if (!try_module_get(nvmem->owner)) { 56869aba794SSrinivas Kandagatla dev_err(&nvmem->dev, 56969aba794SSrinivas Kandagatla "could not increase module refcount for cell %s\n", 57069aba794SSrinivas Kandagatla nvmem->name); 57169aba794SSrinivas Kandagatla 57269aba794SSrinivas Kandagatla mutex_lock(&nvmem_mutex); 57369aba794SSrinivas Kandagatla nvmem->users--; 57469aba794SSrinivas Kandagatla mutex_unlock(&nvmem_mutex); 57569aba794SSrinivas Kandagatla 57669aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 57769aba794SSrinivas Kandagatla } 57869aba794SSrinivas Kandagatla 57969aba794SSrinivas Kandagatla return nvmem; 58069aba794SSrinivas Kandagatla } 58169aba794SSrinivas Kandagatla 58269aba794SSrinivas Kandagatla static void __nvmem_device_put(struct nvmem_device *nvmem) 58369aba794SSrinivas Kandagatla { 58469aba794SSrinivas Kandagatla module_put(nvmem->owner); 58569aba794SSrinivas Kandagatla mutex_lock(&nvmem_mutex); 58669aba794SSrinivas Kandagatla nvmem->users--; 58769aba794SSrinivas Kandagatla mutex_unlock(&nvmem_mutex); 58869aba794SSrinivas Kandagatla } 58969aba794SSrinivas Kandagatla 590e2a5402eSSrinivas Kandagatla static int nvmem_match(struct device *dev, void *data) 591e2a5402eSSrinivas Kandagatla { 592e2a5402eSSrinivas Kandagatla return !strcmp(dev_name(dev), data); 593e2a5402eSSrinivas Kandagatla } 594e2a5402eSSrinivas Kandagatla 595e2a5402eSSrinivas Kandagatla static struct nvmem_device *nvmem_find(const char *name) 596e2a5402eSSrinivas Kandagatla { 597e2a5402eSSrinivas Kandagatla struct device *d; 598e2a5402eSSrinivas Kandagatla 599e2a5402eSSrinivas Kandagatla d = bus_find_device(&nvmem_bus_type, NULL, (void *)name, nvmem_match); 600e2a5402eSSrinivas Kandagatla 601e2a5402eSSrinivas Kandagatla if (!d) 602e2a5402eSSrinivas Kandagatla return NULL; 603e2a5402eSSrinivas Kandagatla 604e2a5402eSSrinivas Kandagatla return to_nvmem_device(d); 605e2a5402eSSrinivas Kandagatla } 606e2a5402eSSrinivas Kandagatla 607e2a5402eSSrinivas Kandagatla #if IS_ENABLED(CONFIG_NVMEM) && IS_ENABLED(CONFIG_OF) 608e2a5402eSSrinivas Kandagatla /** 609e2a5402eSSrinivas Kandagatla * of_nvmem_device_get() - Get nvmem device from a given id 610e2a5402eSSrinivas Kandagatla * 611e2a5402eSSrinivas Kandagatla * @dev node: Device tree node that uses the nvmem device 612e2a5402eSSrinivas Kandagatla * @id: nvmem name from nvmem-names property. 613e2a5402eSSrinivas Kandagatla * 614e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device 615e2a5402eSSrinivas Kandagatla * on success. 616e2a5402eSSrinivas Kandagatla */ 617e2a5402eSSrinivas Kandagatla struct nvmem_device *of_nvmem_device_get(struct device_node *np, const char *id) 618e2a5402eSSrinivas Kandagatla { 619e2a5402eSSrinivas Kandagatla 620e2a5402eSSrinivas Kandagatla struct device_node *nvmem_np; 621e2a5402eSSrinivas Kandagatla int index; 622e2a5402eSSrinivas Kandagatla 623e2a5402eSSrinivas Kandagatla index = of_property_match_string(np, "nvmem-names", id); 624e2a5402eSSrinivas Kandagatla 625e2a5402eSSrinivas Kandagatla nvmem_np = of_parse_phandle(np, "nvmem", index); 626e2a5402eSSrinivas Kandagatla if (!nvmem_np) 627e2a5402eSSrinivas Kandagatla return ERR_PTR(-EINVAL); 628e2a5402eSSrinivas Kandagatla 629e2a5402eSSrinivas Kandagatla return __nvmem_device_get(nvmem_np, NULL, NULL); 630e2a5402eSSrinivas Kandagatla } 631e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_nvmem_device_get); 632e2a5402eSSrinivas Kandagatla #endif 633e2a5402eSSrinivas Kandagatla 634e2a5402eSSrinivas Kandagatla /** 635e2a5402eSSrinivas Kandagatla * nvmem_device_get() - Get nvmem device from a given id 636e2a5402eSSrinivas Kandagatla * 637e2a5402eSSrinivas Kandagatla * @dev : Device that uses the nvmem device 638e2a5402eSSrinivas Kandagatla * @id: nvmem name from nvmem-names property. 639e2a5402eSSrinivas Kandagatla * 640e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device 641e2a5402eSSrinivas Kandagatla * on success. 642e2a5402eSSrinivas Kandagatla */ 643e2a5402eSSrinivas Kandagatla struct nvmem_device *nvmem_device_get(struct device *dev, const char *dev_name) 644e2a5402eSSrinivas Kandagatla { 645e2a5402eSSrinivas Kandagatla if (dev->of_node) { /* try dt first */ 646e2a5402eSSrinivas Kandagatla struct nvmem_device *nvmem; 647e2a5402eSSrinivas Kandagatla 648e2a5402eSSrinivas Kandagatla nvmem = of_nvmem_device_get(dev->of_node, dev_name); 649e2a5402eSSrinivas Kandagatla 650e2a5402eSSrinivas Kandagatla if (!IS_ERR(nvmem) || PTR_ERR(nvmem) == -EPROBE_DEFER) 651e2a5402eSSrinivas Kandagatla return nvmem; 652e2a5402eSSrinivas Kandagatla 653e2a5402eSSrinivas Kandagatla } 654e2a5402eSSrinivas Kandagatla 655e2a5402eSSrinivas Kandagatla return nvmem_find(dev_name); 656e2a5402eSSrinivas Kandagatla } 657e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_get); 658e2a5402eSSrinivas Kandagatla 659e2a5402eSSrinivas Kandagatla static int devm_nvmem_device_match(struct device *dev, void *res, void *data) 660e2a5402eSSrinivas Kandagatla { 661e2a5402eSSrinivas Kandagatla struct nvmem_device **nvmem = res; 662e2a5402eSSrinivas Kandagatla 663e2a5402eSSrinivas Kandagatla if (WARN_ON(!nvmem || !*nvmem)) 664e2a5402eSSrinivas Kandagatla return 0; 665e2a5402eSSrinivas Kandagatla 666e2a5402eSSrinivas Kandagatla return *nvmem == data; 667e2a5402eSSrinivas Kandagatla } 668e2a5402eSSrinivas Kandagatla 669e2a5402eSSrinivas Kandagatla static void devm_nvmem_device_release(struct device *dev, void *res) 670e2a5402eSSrinivas Kandagatla { 671e2a5402eSSrinivas Kandagatla nvmem_device_put(*(struct nvmem_device **)res); 672e2a5402eSSrinivas Kandagatla } 673e2a5402eSSrinivas Kandagatla 674e2a5402eSSrinivas Kandagatla /** 675e2a5402eSSrinivas Kandagatla * devm_nvmem_device_put() - put alredy got nvmem device 676e2a5402eSSrinivas Kandagatla * 677e2a5402eSSrinivas Kandagatla * @nvmem: pointer to nvmem device allocated by devm_nvmem_cell_get(), 678e2a5402eSSrinivas Kandagatla * that needs to be released. 679e2a5402eSSrinivas Kandagatla */ 680e2a5402eSSrinivas Kandagatla void devm_nvmem_device_put(struct device *dev, struct nvmem_device *nvmem) 681e2a5402eSSrinivas Kandagatla { 682e2a5402eSSrinivas Kandagatla int ret; 683e2a5402eSSrinivas Kandagatla 684e2a5402eSSrinivas Kandagatla ret = devres_release(dev, devm_nvmem_device_release, 685e2a5402eSSrinivas Kandagatla devm_nvmem_device_match, nvmem); 686e2a5402eSSrinivas Kandagatla 687e2a5402eSSrinivas Kandagatla WARN_ON(ret); 688e2a5402eSSrinivas Kandagatla } 689e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_device_put); 690e2a5402eSSrinivas Kandagatla 691e2a5402eSSrinivas Kandagatla /** 692e2a5402eSSrinivas Kandagatla * nvmem_device_put() - put alredy got nvmem device 693e2a5402eSSrinivas Kandagatla * 694e2a5402eSSrinivas Kandagatla * @nvmem: pointer to nvmem device that needs to be released. 695e2a5402eSSrinivas Kandagatla */ 696e2a5402eSSrinivas Kandagatla void nvmem_device_put(struct nvmem_device *nvmem) 697e2a5402eSSrinivas Kandagatla { 698e2a5402eSSrinivas Kandagatla __nvmem_device_put(nvmem); 699e2a5402eSSrinivas Kandagatla } 700e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_put); 701e2a5402eSSrinivas Kandagatla 702e2a5402eSSrinivas Kandagatla /** 703e2a5402eSSrinivas Kandagatla * devm_nvmem_device_get() - Get nvmem cell of device form a given id 704e2a5402eSSrinivas Kandagatla * 705e2a5402eSSrinivas Kandagatla * @dev node: Device tree node that uses the nvmem cell 706e2a5402eSSrinivas Kandagatla * @id: nvmem name in nvmems property. 707e2a5402eSSrinivas Kandagatla * 708e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_cell 709e2a5402eSSrinivas Kandagatla * on success. The nvmem_cell will be freed by the automatically once the 710e2a5402eSSrinivas Kandagatla * device is freed. 711e2a5402eSSrinivas Kandagatla */ 712e2a5402eSSrinivas Kandagatla struct nvmem_device *devm_nvmem_device_get(struct device *dev, const char *id) 713e2a5402eSSrinivas Kandagatla { 714e2a5402eSSrinivas Kandagatla struct nvmem_device **ptr, *nvmem; 715e2a5402eSSrinivas Kandagatla 716e2a5402eSSrinivas Kandagatla ptr = devres_alloc(devm_nvmem_device_release, sizeof(*ptr), GFP_KERNEL); 717e2a5402eSSrinivas Kandagatla if (!ptr) 718e2a5402eSSrinivas Kandagatla return ERR_PTR(-ENOMEM); 719e2a5402eSSrinivas Kandagatla 720e2a5402eSSrinivas Kandagatla nvmem = nvmem_device_get(dev, id); 721e2a5402eSSrinivas Kandagatla if (!IS_ERR(nvmem)) { 722e2a5402eSSrinivas Kandagatla *ptr = nvmem; 723e2a5402eSSrinivas Kandagatla devres_add(dev, ptr); 724e2a5402eSSrinivas Kandagatla } else { 725e2a5402eSSrinivas Kandagatla devres_free(ptr); 726e2a5402eSSrinivas Kandagatla } 727e2a5402eSSrinivas Kandagatla 728e2a5402eSSrinivas Kandagatla return nvmem; 729e2a5402eSSrinivas Kandagatla } 730e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_device_get); 731e2a5402eSSrinivas Kandagatla 73269aba794SSrinivas Kandagatla static struct nvmem_cell *nvmem_cell_get_from_list(const char *cell_id) 73369aba794SSrinivas Kandagatla { 73469aba794SSrinivas Kandagatla struct nvmem_cell *cell = NULL; 73569aba794SSrinivas Kandagatla struct nvmem_device *nvmem; 73669aba794SSrinivas Kandagatla 73769aba794SSrinivas Kandagatla nvmem = __nvmem_device_get(NULL, &cell, cell_id); 73869aba794SSrinivas Kandagatla if (IS_ERR(nvmem)) 73969aba794SSrinivas Kandagatla return ERR_CAST(nvmem); 74069aba794SSrinivas Kandagatla 74169aba794SSrinivas Kandagatla return cell; 74269aba794SSrinivas Kandagatla } 74369aba794SSrinivas Kandagatla 74469aba794SSrinivas Kandagatla #if IS_ENABLED(CONFIG_NVMEM) && IS_ENABLED(CONFIG_OF) 74569aba794SSrinivas Kandagatla /** 74669aba794SSrinivas Kandagatla * of_nvmem_cell_get() - Get a nvmem cell from given device node and cell id 74769aba794SSrinivas Kandagatla * 74869aba794SSrinivas Kandagatla * @dev node: Device tree node that uses the nvmem cell 74969aba794SSrinivas Kandagatla * @id: nvmem cell name from nvmem-cell-names property. 75069aba794SSrinivas Kandagatla * 75169aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 75269aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 75369aba794SSrinivas Kandagatla * nvmem_cell_put(). 75469aba794SSrinivas Kandagatla */ 75569aba794SSrinivas Kandagatla struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, 75669aba794SSrinivas Kandagatla const char *name) 75769aba794SSrinivas Kandagatla { 75869aba794SSrinivas Kandagatla struct device_node *cell_np, *nvmem_np; 75969aba794SSrinivas Kandagatla struct nvmem_cell *cell; 76069aba794SSrinivas Kandagatla struct nvmem_device *nvmem; 76169aba794SSrinivas Kandagatla const __be32 *addr; 76269aba794SSrinivas Kandagatla int rval, len, index; 76369aba794SSrinivas Kandagatla 76469aba794SSrinivas Kandagatla index = of_property_match_string(np, "nvmem-cell-names", name); 76569aba794SSrinivas Kandagatla 76669aba794SSrinivas Kandagatla cell_np = of_parse_phandle(np, "nvmem-cells", index); 76769aba794SSrinivas Kandagatla if (!cell_np) 76869aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 76969aba794SSrinivas Kandagatla 77069aba794SSrinivas Kandagatla nvmem_np = of_get_next_parent(cell_np); 77169aba794SSrinivas Kandagatla if (!nvmem_np) 77269aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 77369aba794SSrinivas Kandagatla 77469aba794SSrinivas Kandagatla nvmem = __nvmem_device_get(nvmem_np, NULL, NULL); 77569aba794SSrinivas Kandagatla if (IS_ERR(nvmem)) 77669aba794SSrinivas Kandagatla return ERR_CAST(nvmem); 77769aba794SSrinivas Kandagatla 77869aba794SSrinivas Kandagatla addr = of_get_property(cell_np, "reg", &len); 77969aba794SSrinivas Kandagatla if (!addr || (len < 2 * sizeof(u32))) { 78069aba794SSrinivas Kandagatla dev_err(&nvmem->dev, "nvmem: invalid reg on %s\n", 78169aba794SSrinivas Kandagatla cell_np->full_name); 78269aba794SSrinivas Kandagatla rval = -EINVAL; 78369aba794SSrinivas Kandagatla goto err_mem; 78469aba794SSrinivas Kandagatla } 78569aba794SSrinivas Kandagatla 78669aba794SSrinivas Kandagatla cell = kzalloc(sizeof(*cell), GFP_KERNEL); 78769aba794SSrinivas Kandagatla if (!cell) { 78869aba794SSrinivas Kandagatla rval = -ENOMEM; 78969aba794SSrinivas Kandagatla goto err_mem; 79069aba794SSrinivas Kandagatla } 79169aba794SSrinivas Kandagatla 79269aba794SSrinivas Kandagatla cell->nvmem = nvmem; 79369aba794SSrinivas Kandagatla cell->offset = be32_to_cpup(addr++); 79469aba794SSrinivas Kandagatla cell->bytes = be32_to_cpup(addr); 79569aba794SSrinivas Kandagatla cell->name = cell_np->name; 79669aba794SSrinivas Kandagatla 79769aba794SSrinivas Kandagatla addr = of_get_property(cell_np, "bits", &len); 79869aba794SSrinivas Kandagatla if (addr && len == (2 * sizeof(u32))) { 79969aba794SSrinivas Kandagatla cell->bit_offset = be32_to_cpup(addr++); 80069aba794SSrinivas Kandagatla cell->nbits = be32_to_cpup(addr); 80169aba794SSrinivas Kandagatla } 80269aba794SSrinivas Kandagatla 80369aba794SSrinivas Kandagatla if (cell->nbits) 80469aba794SSrinivas Kandagatla cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset, 80569aba794SSrinivas Kandagatla BITS_PER_BYTE); 80669aba794SSrinivas Kandagatla 80769aba794SSrinivas Kandagatla if (!IS_ALIGNED(cell->offset, nvmem->stride)) { 80869aba794SSrinivas Kandagatla dev_err(&nvmem->dev, 80969aba794SSrinivas Kandagatla "cell %s unaligned to nvmem stride %d\n", 81069aba794SSrinivas Kandagatla cell->name, nvmem->stride); 81169aba794SSrinivas Kandagatla rval = -EINVAL; 81269aba794SSrinivas Kandagatla goto err_sanity; 81369aba794SSrinivas Kandagatla } 81469aba794SSrinivas Kandagatla 81569aba794SSrinivas Kandagatla nvmem_cell_add(cell); 81669aba794SSrinivas Kandagatla 81769aba794SSrinivas Kandagatla return cell; 81869aba794SSrinivas Kandagatla 81969aba794SSrinivas Kandagatla err_sanity: 82069aba794SSrinivas Kandagatla kfree(cell); 82169aba794SSrinivas Kandagatla 82269aba794SSrinivas Kandagatla err_mem: 82369aba794SSrinivas Kandagatla __nvmem_device_put(nvmem); 82469aba794SSrinivas Kandagatla 82569aba794SSrinivas Kandagatla return ERR_PTR(rval); 82669aba794SSrinivas Kandagatla } 82769aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_nvmem_cell_get); 82869aba794SSrinivas Kandagatla #endif 82969aba794SSrinivas Kandagatla 83069aba794SSrinivas Kandagatla /** 83169aba794SSrinivas Kandagatla * nvmem_cell_get() - Get nvmem cell of device form a given cell name 83269aba794SSrinivas Kandagatla * 83369aba794SSrinivas Kandagatla * @dev node: Device tree node that uses the nvmem cell 83469aba794SSrinivas Kandagatla * @id: nvmem cell name to get. 83569aba794SSrinivas Kandagatla * 83669aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 83769aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 83869aba794SSrinivas Kandagatla * nvmem_cell_put(). 83969aba794SSrinivas Kandagatla */ 84069aba794SSrinivas Kandagatla struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *cell_id) 84169aba794SSrinivas Kandagatla { 84269aba794SSrinivas Kandagatla struct nvmem_cell *cell; 84369aba794SSrinivas Kandagatla 84469aba794SSrinivas Kandagatla if (dev->of_node) { /* try dt first */ 84569aba794SSrinivas Kandagatla cell = of_nvmem_cell_get(dev->of_node, cell_id); 84669aba794SSrinivas Kandagatla if (!IS_ERR(cell) || PTR_ERR(cell) == -EPROBE_DEFER) 84769aba794SSrinivas Kandagatla return cell; 84869aba794SSrinivas Kandagatla } 84969aba794SSrinivas Kandagatla 85069aba794SSrinivas Kandagatla return nvmem_cell_get_from_list(cell_id); 85169aba794SSrinivas Kandagatla } 85269aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_get); 85369aba794SSrinivas Kandagatla 85469aba794SSrinivas Kandagatla static void devm_nvmem_cell_release(struct device *dev, void *res) 85569aba794SSrinivas Kandagatla { 85669aba794SSrinivas Kandagatla nvmem_cell_put(*(struct nvmem_cell **)res); 85769aba794SSrinivas Kandagatla } 85869aba794SSrinivas Kandagatla 85969aba794SSrinivas Kandagatla /** 86069aba794SSrinivas Kandagatla * devm_nvmem_cell_get() - Get nvmem cell of device form a given id 86169aba794SSrinivas Kandagatla * 86269aba794SSrinivas Kandagatla * @dev node: Device tree node that uses the nvmem cell 86369aba794SSrinivas Kandagatla * @id: nvmem id in nvmem-names property. 86469aba794SSrinivas Kandagatla * 86569aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 86669aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 86769aba794SSrinivas Kandagatla * automatically once the device is freed. 86869aba794SSrinivas Kandagatla */ 86969aba794SSrinivas Kandagatla struct nvmem_cell *devm_nvmem_cell_get(struct device *dev, const char *id) 87069aba794SSrinivas Kandagatla { 87169aba794SSrinivas Kandagatla struct nvmem_cell **ptr, *cell; 87269aba794SSrinivas Kandagatla 87369aba794SSrinivas Kandagatla ptr = devres_alloc(devm_nvmem_cell_release, sizeof(*ptr), GFP_KERNEL); 87469aba794SSrinivas Kandagatla if (!ptr) 87569aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 87669aba794SSrinivas Kandagatla 87769aba794SSrinivas Kandagatla cell = nvmem_cell_get(dev, id); 87869aba794SSrinivas Kandagatla if (!IS_ERR(cell)) { 87969aba794SSrinivas Kandagatla *ptr = cell; 88069aba794SSrinivas Kandagatla devres_add(dev, ptr); 88169aba794SSrinivas Kandagatla } else { 88269aba794SSrinivas Kandagatla devres_free(ptr); 88369aba794SSrinivas Kandagatla } 88469aba794SSrinivas Kandagatla 88569aba794SSrinivas Kandagatla return cell; 88669aba794SSrinivas Kandagatla } 88769aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_cell_get); 88869aba794SSrinivas Kandagatla 88969aba794SSrinivas Kandagatla static int devm_nvmem_cell_match(struct device *dev, void *res, void *data) 89069aba794SSrinivas Kandagatla { 89169aba794SSrinivas Kandagatla struct nvmem_cell **c = res; 89269aba794SSrinivas Kandagatla 89369aba794SSrinivas Kandagatla if (WARN_ON(!c || !*c)) 89469aba794SSrinivas Kandagatla return 0; 89569aba794SSrinivas Kandagatla 89669aba794SSrinivas Kandagatla return *c == data; 89769aba794SSrinivas Kandagatla } 89869aba794SSrinivas Kandagatla 89969aba794SSrinivas Kandagatla /** 90069aba794SSrinivas Kandagatla * devm_nvmem_cell_put() - Release previously allocated nvmem cell 90169aba794SSrinivas Kandagatla * from devm_nvmem_cell_get. 90269aba794SSrinivas Kandagatla * 90369aba794SSrinivas Kandagatla * @cell: Previously allocated nvmem cell by devm_nvmem_cell_get() 90469aba794SSrinivas Kandagatla */ 90569aba794SSrinivas Kandagatla void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell) 90669aba794SSrinivas Kandagatla { 90769aba794SSrinivas Kandagatla int ret; 90869aba794SSrinivas Kandagatla 90969aba794SSrinivas Kandagatla ret = devres_release(dev, devm_nvmem_cell_release, 91069aba794SSrinivas Kandagatla devm_nvmem_cell_match, cell); 91169aba794SSrinivas Kandagatla 91269aba794SSrinivas Kandagatla WARN_ON(ret); 91369aba794SSrinivas Kandagatla } 91469aba794SSrinivas Kandagatla EXPORT_SYMBOL(devm_nvmem_cell_put); 91569aba794SSrinivas Kandagatla 91669aba794SSrinivas Kandagatla /** 91769aba794SSrinivas Kandagatla * nvmem_cell_put() - Release previously allocated nvmem cell. 91869aba794SSrinivas Kandagatla * 91969aba794SSrinivas Kandagatla * @cell: Previously allocated nvmem cell by nvmem_cell_get() 92069aba794SSrinivas Kandagatla */ 92169aba794SSrinivas Kandagatla void nvmem_cell_put(struct nvmem_cell *cell) 92269aba794SSrinivas Kandagatla { 92369aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 92469aba794SSrinivas Kandagatla 92569aba794SSrinivas Kandagatla __nvmem_device_put(nvmem); 92669aba794SSrinivas Kandagatla nvmem_cell_drop(cell); 92769aba794SSrinivas Kandagatla } 92869aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_put); 92969aba794SSrinivas Kandagatla 93069aba794SSrinivas Kandagatla static inline void nvmem_shift_read_buffer_in_place(struct nvmem_cell *cell, 93169aba794SSrinivas Kandagatla void *buf) 93269aba794SSrinivas Kandagatla { 93369aba794SSrinivas Kandagatla u8 *p, *b; 93469aba794SSrinivas Kandagatla int i, bit_offset = cell->bit_offset; 93569aba794SSrinivas Kandagatla 93669aba794SSrinivas Kandagatla p = b = buf; 93769aba794SSrinivas Kandagatla if (bit_offset) { 93869aba794SSrinivas Kandagatla /* First shift */ 93969aba794SSrinivas Kandagatla *b++ >>= bit_offset; 94069aba794SSrinivas Kandagatla 94169aba794SSrinivas Kandagatla /* setup rest of the bytes if any */ 94269aba794SSrinivas Kandagatla for (i = 1; i < cell->bytes; i++) { 94369aba794SSrinivas Kandagatla /* Get bits from next byte and shift them towards msb */ 94469aba794SSrinivas Kandagatla *p |= *b << (BITS_PER_BYTE - bit_offset); 94569aba794SSrinivas Kandagatla 94669aba794SSrinivas Kandagatla p = b; 94769aba794SSrinivas Kandagatla *b++ >>= bit_offset; 94869aba794SSrinivas Kandagatla } 94969aba794SSrinivas Kandagatla 95069aba794SSrinivas Kandagatla /* result fits in less bytes */ 95169aba794SSrinivas Kandagatla if (cell->bytes != DIV_ROUND_UP(cell->nbits, BITS_PER_BYTE)) 95269aba794SSrinivas Kandagatla *p-- = 0; 95369aba794SSrinivas Kandagatla } 95469aba794SSrinivas Kandagatla /* clear msb bits if any leftover in the last byte */ 95569aba794SSrinivas Kandagatla *p &= GENMASK((cell->nbits%BITS_PER_BYTE) - 1, 0); 95669aba794SSrinivas Kandagatla } 95769aba794SSrinivas Kandagatla 95869aba794SSrinivas Kandagatla static int __nvmem_cell_read(struct nvmem_device *nvmem, 95969aba794SSrinivas Kandagatla struct nvmem_cell *cell, 96069aba794SSrinivas Kandagatla void *buf, size_t *len) 96169aba794SSrinivas Kandagatla { 96269aba794SSrinivas Kandagatla int rc; 96369aba794SSrinivas Kandagatla 964795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, cell->offset, buf, cell->bytes); 96569aba794SSrinivas Kandagatla 966287980e4SArnd Bergmann if (rc) 96769aba794SSrinivas Kandagatla return rc; 96869aba794SSrinivas Kandagatla 96969aba794SSrinivas Kandagatla /* shift bits in-place */ 970cbf854abSAxel Lin if (cell->bit_offset || cell->nbits) 97169aba794SSrinivas Kandagatla nvmem_shift_read_buffer_in_place(cell, buf); 97269aba794SSrinivas Kandagatla 973*3b4a6877SVivek Gautam if (len) 97469aba794SSrinivas Kandagatla *len = cell->bytes; 97569aba794SSrinivas Kandagatla 97669aba794SSrinivas Kandagatla return 0; 97769aba794SSrinivas Kandagatla } 97869aba794SSrinivas Kandagatla 97969aba794SSrinivas Kandagatla /** 98069aba794SSrinivas Kandagatla * nvmem_cell_read() - Read a given nvmem cell 98169aba794SSrinivas Kandagatla * 98269aba794SSrinivas Kandagatla * @cell: nvmem cell to be read. 983*3b4a6877SVivek Gautam * @len: pointer to length of cell which will be populated on successful read; 984*3b4a6877SVivek Gautam * can be NULL. 98569aba794SSrinivas Kandagatla * 986b577fafcSBrian Norris * Return: ERR_PTR() on error or a valid pointer to a buffer on success. The 987b577fafcSBrian Norris * buffer should be freed by the consumer with a kfree(). 98869aba794SSrinivas Kandagatla */ 98969aba794SSrinivas Kandagatla void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len) 99069aba794SSrinivas Kandagatla { 99169aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 99269aba794SSrinivas Kandagatla u8 *buf; 99369aba794SSrinivas Kandagatla int rc; 99469aba794SSrinivas Kandagatla 995795ddd18SSrinivas Kandagatla if (!nvmem) 99669aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 99769aba794SSrinivas Kandagatla 99869aba794SSrinivas Kandagatla buf = kzalloc(cell->bytes, GFP_KERNEL); 99969aba794SSrinivas Kandagatla if (!buf) 100069aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 100169aba794SSrinivas Kandagatla 100269aba794SSrinivas Kandagatla rc = __nvmem_cell_read(nvmem, cell, buf, len); 1003287980e4SArnd Bergmann if (rc) { 100469aba794SSrinivas Kandagatla kfree(buf); 100569aba794SSrinivas Kandagatla return ERR_PTR(rc); 100669aba794SSrinivas Kandagatla } 100769aba794SSrinivas Kandagatla 100869aba794SSrinivas Kandagatla return buf; 100969aba794SSrinivas Kandagatla } 101069aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_read); 101169aba794SSrinivas Kandagatla 101269aba794SSrinivas Kandagatla static inline void *nvmem_cell_prepare_write_buffer(struct nvmem_cell *cell, 101369aba794SSrinivas Kandagatla u8 *_buf, int len) 101469aba794SSrinivas Kandagatla { 101569aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 101669aba794SSrinivas Kandagatla int i, rc, nbits, bit_offset = cell->bit_offset; 101769aba794SSrinivas Kandagatla u8 v, *p, *buf, *b, pbyte, pbits; 101869aba794SSrinivas Kandagatla 101969aba794SSrinivas Kandagatla nbits = cell->nbits; 102069aba794SSrinivas Kandagatla buf = kzalloc(cell->bytes, GFP_KERNEL); 102169aba794SSrinivas Kandagatla if (!buf) 102269aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 102369aba794SSrinivas Kandagatla 102469aba794SSrinivas Kandagatla memcpy(buf, _buf, len); 102569aba794SSrinivas Kandagatla p = b = buf; 102669aba794SSrinivas Kandagatla 102769aba794SSrinivas Kandagatla if (bit_offset) { 102869aba794SSrinivas Kandagatla pbyte = *b; 102969aba794SSrinivas Kandagatla *b <<= bit_offset; 103069aba794SSrinivas Kandagatla 103169aba794SSrinivas Kandagatla /* setup the first byte with lsb bits from nvmem */ 1032795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, cell->offset, &v, 1); 103369aba794SSrinivas Kandagatla *b++ |= GENMASK(bit_offset - 1, 0) & v; 103469aba794SSrinivas Kandagatla 103569aba794SSrinivas Kandagatla /* setup rest of the byte if any */ 103669aba794SSrinivas Kandagatla for (i = 1; i < cell->bytes; i++) { 103769aba794SSrinivas Kandagatla /* Get last byte bits and shift them towards lsb */ 103869aba794SSrinivas Kandagatla pbits = pbyte >> (BITS_PER_BYTE - 1 - bit_offset); 103969aba794SSrinivas Kandagatla pbyte = *b; 104069aba794SSrinivas Kandagatla p = b; 104169aba794SSrinivas Kandagatla *b <<= bit_offset; 104269aba794SSrinivas Kandagatla *b++ |= pbits; 104369aba794SSrinivas Kandagatla } 104469aba794SSrinivas Kandagatla } 104569aba794SSrinivas Kandagatla 104669aba794SSrinivas Kandagatla /* if it's not end on byte boundary */ 104769aba794SSrinivas Kandagatla if ((nbits + bit_offset) % BITS_PER_BYTE) { 104869aba794SSrinivas Kandagatla /* setup the last byte with msb bits from nvmem */ 1049795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, 105069aba794SSrinivas Kandagatla cell->offset + cell->bytes - 1, &v, 1); 105169aba794SSrinivas Kandagatla *p |= GENMASK(7, (nbits + bit_offset) % BITS_PER_BYTE) & v; 105269aba794SSrinivas Kandagatla 105369aba794SSrinivas Kandagatla } 105469aba794SSrinivas Kandagatla 105569aba794SSrinivas Kandagatla return buf; 105669aba794SSrinivas Kandagatla } 105769aba794SSrinivas Kandagatla 105869aba794SSrinivas Kandagatla /** 105969aba794SSrinivas Kandagatla * nvmem_cell_write() - Write to a given nvmem cell 106069aba794SSrinivas Kandagatla * 106169aba794SSrinivas Kandagatla * @cell: nvmem cell to be written. 106269aba794SSrinivas Kandagatla * @buf: Buffer to be written. 106369aba794SSrinivas Kandagatla * @len: length of buffer to be written to nvmem cell. 106469aba794SSrinivas Kandagatla * 106569aba794SSrinivas Kandagatla * Return: length of bytes written or negative on failure. 106669aba794SSrinivas Kandagatla */ 106769aba794SSrinivas Kandagatla int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len) 106869aba794SSrinivas Kandagatla { 106969aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 107069aba794SSrinivas Kandagatla int rc; 107169aba794SSrinivas Kandagatla 1072795ddd18SSrinivas Kandagatla if (!nvmem || nvmem->read_only || 107369aba794SSrinivas Kandagatla (cell->bit_offset == 0 && len != cell->bytes)) 107469aba794SSrinivas Kandagatla return -EINVAL; 107569aba794SSrinivas Kandagatla 107669aba794SSrinivas Kandagatla if (cell->bit_offset || cell->nbits) { 107769aba794SSrinivas Kandagatla buf = nvmem_cell_prepare_write_buffer(cell, buf, len); 107869aba794SSrinivas Kandagatla if (IS_ERR(buf)) 107969aba794SSrinivas Kandagatla return PTR_ERR(buf); 108069aba794SSrinivas Kandagatla } 108169aba794SSrinivas Kandagatla 1082795ddd18SSrinivas Kandagatla rc = nvmem_reg_write(nvmem, cell->offset, buf, cell->bytes); 108369aba794SSrinivas Kandagatla 108469aba794SSrinivas Kandagatla /* free the tmp buffer */ 1085ace22170SAxel Lin if (cell->bit_offset || cell->nbits) 108669aba794SSrinivas Kandagatla kfree(buf); 108769aba794SSrinivas Kandagatla 1088287980e4SArnd Bergmann if (rc) 108969aba794SSrinivas Kandagatla return rc; 109069aba794SSrinivas Kandagatla 109169aba794SSrinivas Kandagatla return len; 109269aba794SSrinivas Kandagatla } 109369aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_write); 109469aba794SSrinivas Kandagatla 1095e2a5402eSSrinivas Kandagatla /** 1096e2a5402eSSrinivas Kandagatla * nvmem_device_cell_read() - Read a given nvmem device and cell 1097e2a5402eSSrinivas Kandagatla * 1098e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to read from. 1099e2a5402eSSrinivas Kandagatla * @info: nvmem cell info to be read. 1100e2a5402eSSrinivas Kandagatla * @buf: buffer pointer which will be populated on successful read. 1101e2a5402eSSrinivas Kandagatla * 1102e2a5402eSSrinivas Kandagatla * Return: length of successful bytes read on success and negative 1103e2a5402eSSrinivas Kandagatla * error code on error. 1104e2a5402eSSrinivas Kandagatla */ 1105e2a5402eSSrinivas Kandagatla ssize_t nvmem_device_cell_read(struct nvmem_device *nvmem, 1106e2a5402eSSrinivas Kandagatla struct nvmem_cell_info *info, void *buf) 1107e2a5402eSSrinivas Kandagatla { 1108e2a5402eSSrinivas Kandagatla struct nvmem_cell cell; 1109e2a5402eSSrinivas Kandagatla int rc; 1110e2a5402eSSrinivas Kandagatla ssize_t len; 1111e2a5402eSSrinivas Kandagatla 1112795ddd18SSrinivas Kandagatla if (!nvmem) 1113e2a5402eSSrinivas Kandagatla return -EINVAL; 1114e2a5402eSSrinivas Kandagatla 1115e2a5402eSSrinivas Kandagatla rc = nvmem_cell_info_to_nvmem_cell(nvmem, info, &cell); 1116287980e4SArnd Bergmann if (rc) 1117e2a5402eSSrinivas Kandagatla return rc; 1118e2a5402eSSrinivas Kandagatla 1119e2a5402eSSrinivas Kandagatla rc = __nvmem_cell_read(nvmem, &cell, buf, &len); 1120287980e4SArnd Bergmann if (rc) 1121e2a5402eSSrinivas Kandagatla return rc; 1122e2a5402eSSrinivas Kandagatla 1123e2a5402eSSrinivas Kandagatla return len; 1124e2a5402eSSrinivas Kandagatla } 1125e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_cell_read); 1126e2a5402eSSrinivas Kandagatla 1127e2a5402eSSrinivas Kandagatla /** 1128e2a5402eSSrinivas Kandagatla * nvmem_device_cell_write() - Write cell to a given nvmem device 1129e2a5402eSSrinivas Kandagatla * 1130e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to be written to. 1131e2a5402eSSrinivas Kandagatla * @info: nvmem cell info to be written 1132e2a5402eSSrinivas Kandagatla * @buf: buffer to be written to cell. 1133e2a5402eSSrinivas Kandagatla * 1134e2a5402eSSrinivas Kandagatla * Return: length of bytes written or negative error code on failure. 1135e2a5402eSSrinivas Kandagatla * */ 1136e2a5402eSSrinivas Kandagatla int nvmem_device_cell_write(struct nvmem_device *nvmem, 1137e2a5402eSSrinivas Kandagatla struct nvmem_cell_info *info, void *buf) 1138e2a5402eSSrinivas Kandagatla { 1139e2a5402eSSrinivas Kandagatla struct nvmem_cell cell; 1140e2a5402eSSrinivas Kandagatla int rc; 1141e2a5402eSSrinivas Kandagatla 1142795ddd18SSrinivas Kandagatla if (!nvmem) 1143e2a5402eSSrinivas Kandagatla return -EINVAL; 1144e2a5402eSSrinivas Kandagatla 1145e2a5402eSSrinivas Kandagatla rc = nvmem_cell_info_to_nvmem_cell(nvmem, info, &cell); 1146287980e4SArnd Bergmann if (rc) 1147e2a5402eSSrinivas Kandagatla return rc; 1148e2a5402eSSrinivas Kandagatla 1149e2a5402eSSrinivas Kandagatla return nvmem_cell_write(&cell, buf, cell.bytes); 1150e2a5402eSSrinivas Kandagatla } 1151e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_cell_write); 1152e2a5402eSSrinivas Kandagatla 1153e2a5402eSSrinivas Kandagatla /** 1154e2a5402eSSrinivas Kandagatla * nvmem_device_read() - Read from a given nvmem device 1155e2a5402eSSrinivas Kandagatla * 1156e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to read from. 1157e2a5402eSSrinivas Kandagatla * @offset: offset in nvmem device. 1158e2a5402eSSrinivas Kandagatla * @bytes: number of bytes to read. 1159e2a5402eSSrinivas Kandagatla * @buf: buffer pointer which will be populated on successful read. 1160e2a5402eSSrinivas Kandagatla * 1161e2a5402eSSrinivas Kandagatla * Return: length of successful bytes read on success and negative 1162e2a5402eSSrinivas Kandagatla * error code on error. 1163e2a5402eSSrinivas Kandagatla */ 1164e2a5402eSSrinivas Kandagatla int nvmem_device_read(struct nvmem_device *nvmem, 1165e2a5402eSSrinivas Kandagatla unsigned int offset, 1166e2a5402eSSrinivas Kandagatla size_t bytes, void *buf) 1167e2a5402eSSrinivas Kandagatla { 1168e2a5402eSSrinivas Kandagatla int rc; 1169e2a5402eSSrinivas Kandagatla 1170795ddd18SSrinivas Kandagatla if (!nvmem) 1171e2a5402eSSrinivas Kandagatla return -EINVAL; 1172e2a5402eSSrinivas Kandagatla 1173795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, offset, buf, bytes); 1174e2a5402eSSrinivas Kandagatla 1175287980e4SArnd Bergmann if (rc) 1176e2a5402eSSrinivas Kandagatla return rc; 1177e2a5402eSSrinivas Kandagatla 1178e2a5402eSSrinivas Kandagatla return bytes; 1179e2a5402eSSrinivas Kandagatla } 1180e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_read); 1181e2a5402eSSrinivas Kandagatla 1182e2a5402eSSrinivas Kandagatla /** 1183e2a5402eSSrinivas Kandagatla * nvmem_device_write() - Write cell to a given nvmem device 1184e2a5402eSSrinivas Kandagatla * 1185e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to be written to. 1186e2a5402eSSrinivas Kandagatla * @offset: offset in nvmem device. 1187e2a5402eSSrinivas Kandagatla * @bytes: number of bytes to write. 1188e2a5402eSSrinivas Kandagatla * @buf: buffer to be written. 1189e2a5402eSSrinivas Kandagatla * 1190e2a5402eSSrinivas Kandagatla * Return: length of bytes written or negative error code on failure. 1191e2a5402eSSrinivas Kandagatla * */ 1192e2a5402eSSrinivas Kandagatla int nvmem_device_write(struct nvmem_device *nvmem, 1193e2a5402eSSrinivas Kandagatla unsigned int offset, 1194e2a5402eSSrinivas Kandagatla size_t bytes, void *buf) 1195e2a5402eSSrinivas Kandagatla { 1196e2a5402eSSrinivas Kandagatla int rc; 1197e2a5402eSSrinivas Kandagatla 1198795ddd18SSrinivas Kandagatla if (!nvmem) 1199e2a5402eSSrinivas Kandagatla return -EINVAL; 1200e2a5402eSSrinivas Kandagatla 1201795ddd18SSrinivas Kandagatla rc = nvmem_reg_write(nvmem, offset, buf, bytes); 1202e2a5402eSSrinivas Kandagatla 1203287980e4SArnd Bergmann if (rc) 1204e2a5402eSSrinivas Kandagatla return rc; 1205e2a5402eSSrinivas Kandagatla 1206e2a5402eSSrinivas Kandagatla 1207e2a5402eSSrinivas Kandagatla return bytes; 1208e2a5402eSSrinivas Kandagatla } 1209e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_write); 1210e2a5402eSSrinivas Kandagatla 1211eace75cfSSrinivas Kandagatla static int __init nvmem_init(void) 1212eace75cfSSrinivas Kandagatla { 1213eace75cfSSrinivas Kandagatla return bus_register(&nvmem_bus_type); 1214eace75cfSSrinivas Kandagatla } 1215eace75cfSSrinivas Kandagatla 1216eace75cfSSrinivas Kandagatla static void __exit nvmem_exit(void) 1217eace75cfSSrinivas Kandagatla { 1218eace75cfSSrinivas Kandagatla bus_unregister(&nvmem_bus_type); 1219eace75cfSSrinivas Kandagatla } 1220eace75cfSSrinivas Kandagatla 1221eace75cfSSrinivas Kandagatla subsys_initcall(nvmem_init); 1222eace75cfSSrinivas Kandagatla module_exit(nvmem_exit); 1223eace75cfSSrinivas Kandagatla 1224eace75cfSSrinivas Kandagatla MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org"); 1225eace75cfSSrinivas Kandagatla MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com"); 1226eace75cfSSrinivas Kandagatla MODULE_DESCRIPTION("nvmem Driver Core"); 1227eace75cfSSrinivas Kandagatla MODULE_LICENSE("GPL v2"); 1228