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) 13838b0774cSGuy Shapiro return -EFBIG; 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 290666d6a36SHeiner Kallweit mutex_lock(&nvmem_cells_mutex); 291666d6a36SHeiner Kallweit 292eace75cfSSrinivas Kandagatla list_for_each_entry(p, &nvmem_cells, node) 293fd086113SDan Carpenter if (!strcmp(p->name, cell_id)) { 294666d6a36SHeiner Kallweit mutex_unlock(&nvmem_cells_mutex); 295eace75cfSSrinivas Kandagatla return p; 296666d6a36SHeiner Kallweit } 297666d6a36SHeiner Kallweit 298666d6a36SHeiner Kallweit mutex_unlock(&nvmem_cells_mutex); 299eace75cfSSrinivas Kandagatla 300eace75cfSSrinivas Kandagatla return NULL; 301eace75cfSSrinivas Kandagatla } 302eace75cfSSrinivas Kandagatla 303eace75cfSSrinivas Kandagatla static void nvmem_cell_drop(struct nvmem_cell *cell) 304eace75cfSSrinivas Kandagatla { 305eace75cfSSrinivas Kandagatla mutex_lock(&nvmem_cells_mutex); 306eace75cfSSrinivas Kandagatla list_del(&cell->node); 307eace75cfSSrinivas Kandagatla mutex_unlock(&nvmem_cells_mutex); 308eace75cfSSrinivas Kandagatla kfree(cell); 309eace75cfSSrinivas Kandagatla } 310eace75cfSSrinivas Kandagatla 311eace75cfSSrinivas Kandagatla static void nvmem_device_remove_all_cells(const struct nvmem_device *nvmem) 312eace75cfSSrinivas Kandagatla { 313eace75cfSSrinivas Kandagatla struct nvmem_cell *cell; 314eace75cfSSrinivas Kandagatla struct list_head *p, *n; 315eace75cfSSrinivas Kandagatla 316eace75cfSSrinivas Kandagatla list_for_each_safe(p, n, &nvmem_cells) { 317eace75cfSSrinivas Kandagatla cell = list_entry(p, struct nvmem_cell, node); 318eace75cfSSrinivas Kandagatla if (cell->nvmem == nvmem) 319eace75cfSSrinivas Kandagatla nvmem_cell_drop(cell); 320eace75cfSSrinivas Kandagatla } 321eace75cfSSrinivas Kandagatla } 322eace75cfSSrinivas Kandagatla 323eace75cfSSrinivas Kandagatla static void nvmem_cell_add(struct nvmem_cell *cell) 324eace75cfSSrinivas Kandagatla { 325eace75cfSSrinivas Kandagatla mutex_lock(&nvmem_cells_mutex); 326eace75cfSSrinivas Kandagatla list_add_tail(&cell->node, &nvmem_cells); 327eace75cfSSrinivas Kandagatla mutex_unlock(&nvmem_cells_mutex); 328eace75cfSSrinivas Kandagatla } 329eace75cfSSrinivas Kandagatla 330eace75cfSSrinivas Kandagatla static int nvmem_cell_info_to_nvmem_cell(struct nvmem_device *nvmem, 331eace75cfSSrinivas Kandagatla const struct nvmem_cell_info *info, 332eace75cfSSrinivas Kandagatla struct nvmem_cell *cell) 333eace75cfSSrinivas Kandagatla { 334eace75cfSSrinivas Kandagatla cell->nvmem = nvmem; 335eace75cfSSrinivas Kandagatla cell->offset = info->offset; 336eace75cfSSrinivas Kandagatla cell->bytes = info->bytes; 337eace75cfSSrinivas Kandagatla cell->name = info->name; 338eace75cfSSrinivas Kandagatla 339eace75cfSSrinivas Kandagatla cell->bit_offset = info->bit_offset; 340eace75cfSSrinivas Kandagatla cell->nbits = info->nbits; 341eace75cfSSrinivas Kandagatla 342eace75cfSSrinivas Kandagatla if (cell->nbits) 343eace75cfSSrinivas Kandagatla cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset, 344eace75cfSSrinivas Kandagatla BITS_PER_BYTE); 345eace75cfSSrinivas Kandagatla 346eace75cfSSrinivas Kandagatla if (!IS_ALIGNED(cell->offset, nvmem->stride)) { 347eace75cfSSrinivas Kandagatla dev_err(&nvmem->dev, 348eace75cfSSrinivas Kandagatla "cell %s unaligned to nvmem stride %d\n", 349eace75cfSSrinivas Kandagatla cell->name, nvmem->stride); 350eace75cfSSrinivas Kandagatla return -EINVAL; 351eace75cfSSrinivas Kandagatla } 352eace75cfSSrinivas Kandagatla 353eace75cfSSrinivas Kandagatla return 0; 354eace75cfSSrinivas Kandagatla } 355eace75cfSSrinivas Kandagatla 356b3db17e4SAndrew Lunn /** 357b3db17e4SAndrew Lunn * nvmem_add_cells() - Add cell information to an nvmem device 358b3db17e4SAndrew Lunn * 359b3db17e4SAndrew Lunn * @nvmem: nvmem device to add cells to. 360b3db17e4SAndrew Lunn * @info: nvmem cell info to add to the device 361b3db17e4SAndrew Lunn * @ncells: number of cells in info 362b3db17e4SAndrew Lunn * 363b3db17e4SAndrew Lunn * Return: 0 or negative error code on failure. 364b3db17e4SAndrew Lunn */ 365b3db17e4SAndrew Lunn int nvmem_add_cells(struct nvmem_device *nvmem, 366b3db17e4SAndrew Lunn const struct nvmem_cell_info *info, 367b3db17e4SAndrew Lunn int ncells) 368eace75cfSSrinivas Kandagatla { 369eace75cfSSrinivas Kandagatla struct nvmem_cell **cells; 370eace75cfSSrinivas Kandagatla int i, rval; 371eace75cfSSrinivas Kandagatla 372b3db17e4SAndrew Lunn cells = kcalloc(ncells, sizeof(*cells), GFP_KERNEL); 373eace75cfSSrinivas Kandagatla if (!cells) 374eace75cfSSrinivas Kandagatla return -ENOMEM; 375eace75cfSSrinivas Kandagatla 376b3db17e4SAndrew Lunn for (i = 0; i < ncells; i++) { 377eace75cfSSrinivas Kandagatla cells[i] = kzalloc(sizeof(**cells), GFP_KERNEL); 378eace75cfSSrinivas Kandagatla if (!cells[i]) { 379eace75cfSSrinivas Kandagatla rval = -ENOMEM; 380eace75cfSSrinivas Kandagatla goto err; 381eace75cfSSrinivas Kandagatla } 382eace75cfSSrinivas Kandagatla 383eace75cfSSrinivas Kandagatla rval = nvmem_cell_info_to_nvmem_cell(nvmem, &info[i], cells[i]); 384287980e4SArnd Bergmann if (rval) { 385eace75cfSSrinivas Kandagatla kfree(cells[i]); 386eace75cfSSrinivas Kandagatla goto err; 387eace75cfSSrinivas Kandagatla } 388eace75cfSSrinivas Kandagatla 389eace75cfSSrinivas Kandagatla nvmem_cell_add(cells[i]); 390eace75cfSSrinivas Kandagatla } 391eace75cfSSrinivas Kandagatla 392b3db17e4SAndrew Lunn nvmem->ncells = ncells; 393eace75cfSSrinivas Kandagatla /* remove tmp array */ 394eace75cfSSrinivas Kandagatla kfree(cells); 395eace75cfSSrinivas Kandagatla 396eace75cfSSrinivas Kandagatla return 0; 397eace75cfSSrinivas Kandagatla err: 398dfdf1414SRasmus Villemoes while (i--) 399eace75cfSSrinivas Kandagatla nvmem_cell_drop(cells[i]); 400eace75cfSSrinivas Kandagatla 401dfdf1414SRasmus Villemoes kfree(cells); 402dfdf1414SRasmus Villemoes 403eace75cfSSrinivas Kandagatla return rval; 404eace75cfSSrinivas Kandagatla } 405b3db17e4SAndrew Lunn EXPORT_SYMBOL_GPL(nvmem_add_cells); 406eace75cfSSrinivas Kandagatla 407b6c217abSAndrew Lunn /* 408b6c217abSAndrew Lunn * nvmem_setup_compat() - Create an additional binary entry in 409b6c217abSAndrew Lunn * drivers sys directory, to be backwards compatible with the older 410b6c217abSAndrew Lunn * drivers/misc/eeprom drivers. 411b6c217abSAndrew Lunn */ 412b6c217abSAndrew Lunn static int nvmem_setup_compat(struct nvmem_device *nvmem, 413b6c217abSAndrew Lunn const struct nvmem_config *config) 414b6c217abSAndrew Lunn { 415b6c217abSAndrew Lunn int rval; 416b6c217abSAndrew Lunn 417b6c217abSAndrew Lunn if (!config->base_dev) 418b6c217abSAndrew Lunn return -EINVAL; 419b6c217abSAndrew Lunn 420b6c217abSAndrew Lunn if (nvmem->read_only) 421b6c217abSAndrew Lunn nvmem->eeprom = bin_attr_ro_root_nvmem; 422b6c217abSAndrew Lunn else 423b6c217abSAndrew Lunn nvmem->eeprom = bin_attr_rw_root_nvmem; 424b6c217abSAndrew Lunn nvmem->eeprom.attr.name = "eeprom"; 425b6c217abSAndrew Lunn nvmem->eeprom.size = nvmem->size; 426b6c217abSAndrew Lunn #ifdef CONFIG_DEBUG_LOCK_ALLOC 427b6c217abSAndrew Lunn nvmem->eeprom.attr.key = &eeprom_lock_key; 428b6c217abSAndrew Lunn #endif 429b6c217abSAndrew Lunn nvmem->eeprom.private = &nvmem->dev; 430b6c217abSAndrew Lunn nvmem->base_dev = config->base_dev; 431b6c217abSAndrew Lunn 432b6c217abSAndrew Lunn rval = device_create_bin_file(nvmem->base_dev, &nvmem->eeprom); 433b6c217abSAndrew Lunn if (rval) { 434b6c217abSAndrew Lunn dev_err(&nvmem->dev, 435b6c217abSAndrew Lunn "Failed to create eeprom binary file %d\n", rval); 436b6c217abSAndrew Lunn return rval; 437b6c217abSAndrew Lunn } 438b6c217abSAndrew Lunn 439b6c217abSAndrew Lunn nvmem->flags |= FLAG_COMPAT; 440b6c217abSAndrew Lunn 441b6c217abSAndrew Lunn return 0; 442b6c217abSAndrew Lunn } 443b6c217abSAndrew Lunn 444eace75cfSSrinivas Kandagatla /** 445eace75cfSSrinivas Kandagatla * nvmem_register() - Register a nvmem device for given nvmem_config. 446eace75cfSSrinivas Kandagatla * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem 447eace75cfSSrinivas Kandagatla * 448eace75cfSSrinivas Kandagatla * @config: nvmem device configuration with which nvmem device is created. 449eace75cfSSrinivas Kandagatla * 450eace75cfSSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device 451eace75cfSSrinivas Kandagatla * on success. 452eace75cfSSrinivas Kandagatla */ 453eace75cfSSrinivas Kandagatla 454eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem_register(const struct nvmem_config *config) 455eace75cfSSrinivas Kandagatla { 456eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem; 457eace75cfSSrinivas Kandagatla int rval; 458eace75cfSSrinivas Kandagatla 459eace75cfSSrinivas Kandagatla if (!config->dev) 460eace75cfSSrinivas Kandagatla return ERR_PTR(-EINVAL); 461eace75cfSSrinivas Kandagatla 462eace75cfSSrinivas Kandagatla nvmem = kzalloc(sizeof(*nvmem), GFP_KERNEL); 463eace75cfSSrinivas Kandagatla if (!nvmem) 464eace75cfSSrinivas Kandagatla return ERR_PTR(-ENOMEM); 465eace75cfSSrinivas Kandagatla 466eace75cfSSrinivas Kandagatla rval = ida_simple_get(&nvmem_ida, 0, 0, GFP_KERNEL); 467eace75cfSSrinivas Kandagatla if (rval < 0) { 468eace75cfSSrinivas Kandagatla kfree(nvmem); 469eace75cfSSrinivas Kandagatla return ERR_PTR(rval); 470eace75cfSSrinivas Kandagatla } 471eace75cfSSrinivas Kandagatla 472eace75cfSSrinivas Kandagatla nvmem->id = rval; 473eace75cfSSrinivas Kandagatla nvmem->owner = config->owner; 47417eb18d6SMasahiro Yamada if (!nvmem->owner && config->dev->driver) 47517eb18d6SMasahiro Yamada nvmem->owner = config->dev->driver->owner; 47699897efdSHeiner Kallweit nvmem->stride = config->stride ?: 1; 47799897efdSHeiner Kallweit nvmem->word_size = config->word_size ?: 1; 478795ddd18SSrinivas Kandagatla nvmem->size = config->size; 479eace75cfSSrinivas Kandagatla nvmem->dev.type = &nvmem_provider_type; 480eace75cfSSrinivas Kandagatla nvmem->dev.bus = &nvmem_bus_type; 481eace75cfSSrinivas Kandagatla nvmem->dev.parent = config->dev; 482795ddd18SSrinivas Kandagatla nvmem->priv = config->priv; 483795ddd18SSrinivas Kandagatla nvmem->reg_read = config->reg_read; 484795ddd18SSrinivas Kandagatla nvmem->reg_write = config->reg_write; 485fc2f9970SHeiner Kallweit nvmem->dev.of_node = config->dev->of_node; 486fd0f4906SAndrey Smirnov 487fd0f4906SAndrey Smirnov if (config->id == -1 && config->name) { 488fd0f4906SAndrey Smirnov dev_set_name(&nvmem->dev, "%s", config->name); 489fd0f4906SAndrey Smirnov } else { 490eace75cfSSrinivas Kandagatla dev_set_name(&nvmem->dev, "%s%d", 4915253193dSAban Bedel config->name ? : "nvmem", 4925253193dSAban Bedel config->name ? config->id : nvmem->id); 493fd0f4906SAndrey Smirnov } 494eace75cfSSrinivas Kandagatla 495fc2f9970SHeiner Kallweit nvmem->read_only = device_property_present(config->dev, "read-only") | 496eace75cfSSrinivas Kandagatla config->read_only; 497eace75cfSSrinivas Kandagatla 498811b0d65SAndrew Lunn if (config->root_only) 499811b0d65SAndrew Lunn nvmem->dev.groups = nvmem->read_only ? 500811b0d65SAndrew Lunn nvmem_ro_root_dev_groups : 501811b0d65SAndrew Lunn nvmem_rw_root_dev_groups; 502811b0d65SAndrew Lunn else 503811b0d65SAndrew Lunn nvmem->dev.groups = nvmem->read_only ? 504811b0d65SAndrew Lunn nvmem_ro_dev_groups : 505eace75cfSSrinivas Kandagatla nvmem_rw_dev_groups; 506eace75cfSSrinivas Kandagatla 507eace75cfSSrinivas Kandagatla device_initialize(&nvmem->dev); 508eace75cfSSrinivas Kandagatla 509eace75cfSSrinivas Kandagatla dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name); 510eace75cfSSrinivas Kandagatla 511eace75cfSSrinivas Kandagatla rval = device_add(&nvmem->dev); 512b6c217abSAndrew Lunn if (rval) 5133360acdfSJohan Hovold goto err_put_device; 514b6c217abSAndrew Lunn 515b6c217abSAndrew Lunn if (config->compat) { 516b6c217abSAndrew Lunn rval = nvmem_setup_compat(nvmem, config); 517b6c217abSAndrew Lunn if (rval) 5183360acdfSJohan Hovold goto err_device_del; 519eace75cfSSrinivas Kandagatla } 520eace75cfSSrinivas Kandagatla 521eace75cfSSrinivas Kandagatla if (config->cells) 522b3db17e4SAndrew Lunn nvmem_add_cells(nvmem, config->cells, config->ncells); 523eace75cfSSrinivas Kandagatla 524eace75cfSSrinivas Kandagatla return nvmem; 5253360acdfSJohan Hovold 5263360acdfSJohan Hovold err_device_del: 5273360acdfSJohan Hovold device_del(&nvmem->dev); 5283360acdfSJohan Hovold err_put_device: 5293360acdfSJohan Hovold put_device(&nvmem->dev); 5303360acdfSJohan Hovold 531b6c217abSAndrew Lunn return ERR_PTR(rval); 532eace75cfSSrinivas Kandagatla } 533eace75cfSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_register); 534eace75cfSSrinivas Kandagatla 535eace75cfSSrinivas Kandagatla /** 536eace75cfSSrinivas Kandagatla * nvmem_unregister() - Unregister previously registered nvmem device 537eace75cfSSrinivas Kandagatla * 538eace75cfSSrinivas Kandagatla * @nvmem: Pointer to previously registered nvmem device. 539eace75cfSSrinivas Kandagatla * 540eace75cfSSrinivas Kandagatla * Return: Will be an negative on error or a zero on success. 541eace75cfSSrinivas Kandagatla */ 542eace75cfSSrinivas Kandagatla int nvmem_unregister(struct nvmem_device *nvmem) 543eace75cfSSrinivas Kandagatla { 54469aba794SSrinivas Kandagatla mutex_lock(&nvmem_mutex); 54569aba794SSrinivas Kandagatla if (nvmem->users) { 54669aba794SSrinivas Kandagatla mutex_unlock(&nvmem_mutex); 547eace75cfSSrinivas Kandagatla return -EBUSY; 54869aba794SSrinivas Kandagatla } 54969aba794SSrinivas Kandagatla mutex_unlock(&nvmem_mutex); 550eace75cfSSrinivas Kandagatla 551b6c217abSAndrew Lunn if (nvmem->flags & FLAG_COMPAT) 552b6c217abSAndrew Lunn device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); 553b6c217abSAndrew Lunn 554eace75cfSSrinivas Kandagatla nvmem_device_remove_all_cells(nvmem); 555eace75cfSSrinivas Kandagatla device_del(&nvmem->dev); 55679fbf046SAndrey Smirnov put_device(&nvmem->dev); 557eace75cfSSrinivas Kandagatla 558eace75cfSSrinivas Kandagatla return 0; 559eace75cfSSrinivas Kandagatla } 560eace75cfSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_unregister); 561eace75cfSSrinivas Kandagatla 562f1f50ecaSAndrey Smirnov static void devm_nvmem_release(struct device *dev, void *res) 563f1f50ecaSAndrey Smirnov { 564f1f50ecaSAndrey Smirnov WARN_ON(nvmem_unregister(*(struct nvmem_device **)res)); 565f1f50ecaSAndrey Smirnov } 566f1f50ecaSAndrey Smirnov 567f1f50ecaSAndrey Smirnov /** 568f1f50ecaSAndrey Smirnov * devm_nvmem_register() - Register a managed nvmem device for given 569f1f50ecaSAndrey Smirnov * nvmem_config. 570f1f50ecaSAndrey Smirnov * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem 571f1f50ecaSAndrey Smirnov * 572*b378c779SSrinivas Kandagatla * @dev: Device that uses the nvmem device. 573f1f50ecaSAndrey Smirnov * @config: nvmem device configuration with which nvmem device is created. 574f1f50ecaSAndrey Smirnov * 575f1f50ecaSAndrey Smirnov * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device 576f1f50ecaSAndrey Smirnov * on success. 577f1f50ecaSAndrey Smirnov */ 578f1f50ecaSAndrey Smirnov struct nvmem_device *devm_nvmem_register(struct device *dev, 579f1f50ecaSAndrey Smirnov const struct nvmem_config *config) 580f1f50ecaSAndrey Smirnov { 581f1f50ecaSAndrey Smirnov struct nvmem_device **ptr, *nvmem; 582f1f50ecaSAndrey Smirnov 583f1f50ecaSAndrey Smirnov ptr = devres_alloc(devm_nvmem_release, sizeof(*ptr), GFP_KERNEL); 584f1f50ecaSAndrey Smirnov if (!ptr) 585f1f50ecaSAndrey Smirnov return ERR_PTR(-ENOMEM); 586f1f50ecaSAndrey Smirnov 587f1f50ecaSAndrey Smirnov nvmem = nvmem_register(config); 588f1f50ecaSAndrey Smirnov 589f1f50ecaSAndrey Smirnov if (!IS_ERR(nvmem)) { 590f1f50ecaSAndrey Smirnov *ptr = nvmem; 591f1f50ecaSAndrey Smirnov devres_add(dev, ptr); 592f1f50ecaSAndrey Smirnov } else { 593f1f50ecaSAndrey Smirnov devres_free(ptr); 594f1f50ecaSAndrey Smirnov } 595f1f50ecaSAndrey Smirnov 596f1f50ecaSAndrey Smirnov return nvmem; 597f1f50ecaSAndrey Smirnov } 598f1f50ecaSAndrey Smirnov EXPORT_SYMBOL_GPL(devm_nvmem_register); 599f1f50ecaSAndrey Smirnov 600f1f50ecaSAndrey Smirnov static int devm_nvmem_match(struct device *dev, void *res, void *data) 601f1f50ecaSAndrey Smirnov { 602f1f50ecaSAndrey Smirnov struct nvmem_device **r = res; 603f1f50ecaSAndrey Smirnov 604f1f50ecaSAndrey Smirnov return *r == data; 605f1f50ecaSAndrey Smirnov } 606f1f50ecaSAndrey Smirnov 607f1f50ecaSAndrey Smirnov /** 608f1f50ecaSAndrey Smirnov * devm_nvmem_unregister() - Unregister previously registered managed nvmem 609f1f50ecaSAndrey Smirnov * device. 610f1f50ecaSAndrey Smirnov * 611*b378c779SSrinivas Kandagatla * @dev: Device that uses the nvmem device. 612f1f50ecaSAndrey Smirnov * @nvmem: Pointer to previously registered nvmem device. 613f1f50ecaSAndrey Smirnov * 614f1f50ecaSAndrey Smirnov * Return: Will be an negative on error or a zero on success. 615f1f50ecaSAndrey Smirnov */ 616f1f50ecaSAndrey Smirnov int devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem) 617f1f50ecaSAndrey Smirnov { 618f1f50ecaSAndrey Smirnov return devres_release(dev, devm_nvmem_release, devm_nvmem_match, nvmem); 619f1f50ecaSAndrey Smirnov } 620f1f50ecaSAndrey Smirnov EXPORT_SYMBOL(devm_nvmem_unregister); 621f1f50ecaSAndrey Smirnov 622f1f50ecaSAndrey Smirnov 62369aba794SSrinivas Kandagatla static struct nvmem_device *__nvmem_device_get(struct device_node *np, 62469aba794SSrinivas Kandagatla struct nvmem_cell **cellp, 62569aba794SSrinivas Kandagatla const char *cell_id) 62669aba794SSrinivas Kandagatla { 62769aba794SSrinivas Kandagatla struct nvmem_device *nvmem = NULL; 62869aba794SSrinivas Kandagatla 62969aba794SSrinivas Kandagatla mutex_lock(&nvmem_mutex); 63069aba794SSrinivas Kandagatla 63169aba794SSrinivas Kandagatla if (np) { 63269aba794SSrinivas Kandagatla nvmem = of_nvmem_find(np); 63369aba794SSrinivas Kandagatla if (!nvmem) { 63469aba794SSrinivas Kandagatla mutex_unlock(&nvmem_mutex); 63569aba794SSrinivas Kandagatla return ERR_PTR(-EPROBE_DEFER); 63669aba794SSrinivas Kandagatla } 63769aba794SSrinivas Kandagatla } else { 63869aba794SSrinivas Kandagatla struct nvmem_cell *cell = nvmem_find_cell(cell_id); 63969aba794SSrinivas Kandagatla 64069aba794SSrinivas Kandagatla if (cell) { 64169aba794SSrinivas Kandagatla nvmem = cell->nvmem; 64269aba794SSrinivas Kandagatla *cellp = cell; 64369aba794SSrinivas Kandagatla } 64469aba794SSrinivas Kandagatla 64569aba794SSrinivas Kandagatla if (!nvmem) { 64669aba794SSrinivas Kandagatla mutex_unlock(&nvmem_mutex); 64769aba794SSrinivas Kandagatla return ERR_PTR(-ENOENT); 64869aba794SSrinivas Kandagatla } 64969aba794SSrinivas Kandagatla } 65069aba794SSrinivas Kandagatla 65169aba794SSrinivas Kandagatla nvmem->users++; 65269aba794SSrinivas Kandagatla mutex_unlock(&nvmem_mutex); 65369aba794SSrinivas Kandagatla 65469aba794SSrinivas Kandagatla if (!try_module_get(nvmem->owner)) { 65569aba794SSrinivas Kandagatla dev_err(&nvmem->dev, 65669aba794SSrinivas Kandagatla "could not increase module refcount for cell %s\n", 65769aba794SSrinivas Kandagatla nvmem->name); 65869aba794SSrinivas Kandagatla 65969aba794SSrinivas Kandagatla mutex_lock(&nvmem_mutex); 66069aba794SSrinivas Kandagatla nvmem->users--; 66169aba794SSrinivas Kandagatla mutex_unlock(&nvmem_mutex); 66269aba794SSrinivas Kandagatla 66369aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 66469aba794SSrinivas Kandagatla } 66569aba794SSrinivas Kandagatla 66669aba794SSrinivas Kandagatla return nvmem; 66769aba794SSrinivas Kandagatla } 66869aba794SSrinivas Kandagatla 66969aba794SSrinivas Kandagatla static void __nvmem_device_put(struct nvmem_device *nvmem) 67069aba794SSrinivas Kandagatla { 67169aba794SSrinivas Kandagatla module_put(nvmem->owner); 67269aba794SSrinivas Kandagatla mutex_lock(&nvmem_mutex); 67369aba794SSrinivas Kandagatla nvmem->users--; 67469aba794SSrinivas Kandagatla mutex_unlock(&nvmem_mutex); 67569aba794SSrinivas Kandagatla } 67669aba794SSrinivas Kandagatla 677e2a5402eSSrinivas Kandagatla static struct nvmem_device *nvmem_find(const char *name) 678e2a5402eSSrinivas Kandagatla { 679e2a5402eSSrinivas Kandagatla struct device *d; 680e2a5402eSSrinivas Kandagatla 6819f3044c3SLukas Wunner d = bus_find_device_by_name(&nvmem_bus_type, NULL, name); 682e2a5402eSSrinivas Kandagatla 683e2a5402eSSrinivas Kandagatla if (!d) 684e2a5402eSSrinivas Kandagatla return NULL; 685e2a5402eSSrinivas Kandagatla 686e2a5402eSSrinivas Kandagatla return to_nvmem_device(d); 687e2a5402eSSrinivas Kandagatla } 688e2a5402eSSrinivas Kandagatla 689e701c67cSMasahiro Yamada #if IS_ENABLED(CONFIG_OF) 690e2a5402eSSrinivas Kandagatla /** 691e2a5402eSSrinivas Kandagatla * of_nvmem_device_get() - Get nvmem device from a given id 692e2a5402eSSrinivas Kandagatla * 69329143268SVivek Gautam * @np: Device tree node that uses the nvmem device. 694e2a5402eSSrinivas Kandagatla * @id: nvmem name from nvmem-names property. 695e2a5402eSSrinivas Kandagatla * 696e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device 697e2a5402eSSrinivas Kandagatla * on success. 698e2a5402eSSrinivas Kandagatla */ 699e2a5402eSSrinivas Kandagatla struct nvmem_device *of_nvmem_device_get(struct device_node *np, const char *id) 700e2a5402eSSrinivas Kandagatla { 701e2a5402eSSrinivas Kandagatla 702e2a5402eSSrinivas Kandagatla struct device_node *nvmem_np; 703e2a5402eSSrinivas Kandagatla int index; 704e2a5402eSSrinivas Kandagatla 705e2a5402eSSrinivas Kandagatla index = of_property_match_string(np, "nvmem-names", id); 706e2a5402eSSrinivas Kandagatla 707e2a5402eSSrinivas Kandagatla nvmem_np = of_parse_phandle(np, "nvmem", index); 708e2a5402eSSrinivas Kandagatla if (!nvmem_np) 709e2a5402eSSrinivas Kandagatla return ERR_PTR(-EINVAL); 710e2a5402eSSrinivas Kandagatla 711e2a5402eSSrinivas Kandagatla return __nvmem_device_get(nvmem_np, NULL, NULL); 712e2a5402eSSrinivas Kandagatla } 713e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_nvmem_device_get); 714e2a5402eSSrinivas Kandagatla #endif 715e2a5402eSSrinivas Kandagatla 716e2a5402eSSrinivas Kandagatla /** 717e2a5402eSSrinivas Kandagatla * nvmem_device_get() - Get nvmem device from a given id 718e2a5402eSSrinivas Kandagatla * 71929143268SVivek Gautam * @dev: Device that uses the nvmem device. 72029143268SVivek Gautam * @dev_name: name of the requested nvmem device. 721e2a5402eSSrinivas Kandagatla * 722e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device 723e2a5402eSSrinivas Kandagatla * on success. 724e2a5402eSSrinivas Kandagatla */ 725e2a5402eSSrinivas Kandagatla struct nvmem_device *nvmem_device_get(struct device *dev, const char *dev_name) 726e2a5402eSSrinivas Kandagatla { 727e2a5402eSSrinivas Kandagatla if (dev->of_node) { /* try dt first */ 728e2a5402eSSrinivas Kandagatla struct nvmem_device *nvmem; 729e2a5402eSSrinivas Kandagatla 730e2a5402eSSrinivas Kandagatla nvmem = of_nvmem_device_get(dev->of_node, dev_name); 731e2a5402eSSrinivas Kandagatla 732e2a5402eSSrinivas Kandagatla if (!IS_ERR(nvmem) || PTR_ERR(nvmem) == -EPROBE_DEFER) 733e2a5402eSSrinivas Kandagatla return nvmem; 734e2a5402eSSrinivas Kandagatla 735e2a5402eSSrinivas Kandagatla } 736e2a5402eSSrinivas Kandagatla 737e2a5402eSSrinivas Kandagatla return nvmem_find(dev_name); 738e2a5402eSSrinivas Kandagatla } 739e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_get); 740e2a5402eSSrinivas Kandagatla 741e2a5402eSSrinivas Kandagatla static int devm_nvmem_device_match(struct device *dev, void *res, void *data) 742e2a5402eSSrinivas Kandagatla { 743e2a5402eSSrinivas Kandagatla struct nvmem_device **nvmem = res; 744e2a5402eSSrinivas Kandagatla 745e2a5402eSSrinivas Kandagatla if (WARN_ON(!nvmem || !*nvmem)) 746e2a5402eSSrinivas Kandagatla return 0; 747e2a5402eSSrinivas Kandagatla 748e2a5402eSSrinivas Kandagatla return *nvmem == data; 749e2a5402eSSrinivas Kandagatla } 750e2a5402eSSrinivas Kandagatla 751e2a5402eSSrinivas Kandagatla static void devm_nvmem_device_release(struct device *dev, void *res) 752e2a5402eSSrinivas Kandagatla { 753e2a5402eSSrinivas Kandagatla nvmem_device_put(*(struct nvmem_device **)res); 754e2a5402eSSrinivas Kandagatla } 755e2a5402eSSrinivas Kandagatla 756e2a5402eSSrinivas Kandagatla /** 757e2a5402eSSrinivas Kandagatla * devm_nvmem_device_put() - put alredy got nvmem device 758e2a5402eSSrinivas Kandagatla * 75929143268SVivek Gautam * @dev: Device that uses the nvmem device. 760e2a5402eSSrinivas Kandagatla * @nvmem: pointer to nvmem device allocated by devm_nvmem_cell_get(), 761e2a5402eSSrinivas Kandagatla * that needs to be released. 762e2a5402eSSrinivas Kandagatla */ 763e2a5402eSSrinivas Kandagatla void devm_nvmem_device_put(struct device *dev, struct nvmem_device *nvmem) 764e2a5402eSSrinivas Kandagatla { 765e2a5402eSSrinivas Kandagatla int ret; 766e2a5402eSSrinivas Kandagatla 767e2a5402eSSrinivas Kandagatla ret = devres_release(dev, devm_nvmem_device_release, 768e2a5402eSSrinivas Kandagatla devm_nvmem_device_match, nvmem); 769e2a5402eSSrinivas Kandagatla 770e2a5402eSSrinivas Kandagatla WARN_ON(ret); 771e2a5402eSSrinivas Kandagatla } 772e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_device_put); 773e2a5402eSSrinivas Kandagatla 774e2a5402eSSrinivas Kandagatla /** 775e2a5402eSSrinivas Kandagatla * nvmem_device_put() - put alredy got nvmem device 776e2a5402eSSrinivas Kandagatla * 777e2a5402eSSrinivas Kandagatla * @nvmem: pointer to nvmem device that needs to be released. 778e2a5402eSSrinivas Kandagatla */ 779e2a5402eSSrinivas Kandagatla void nvmem_device_put(struct nvmem_device *nvmem) 780e2a5402eSSrinivas Kandagatla { 781e2a5402eSSrinivas Kandagatla __nvmem_device_put(nvmem); 782e2a5402eSSrinivas Kandagatla } 783e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_put); 784e2a5402eSSrinivas Kandagatla 785e2a5402eSSrinivas Kandagatla /** 786e2a5402eSSrinivas Kandagatla * devm_nvmem_device_get() - Get nvmem cell of device form a given id 787e2a5402eSSrinivas Kandagatla * 78829143268SVivek Gautam * @dev: Device that requests the nvmem device. 78929143268SVivek Gautam * @id: name id for the requested nvmem device. 790e2a5402eSSrinivas Kandagatla * 791e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_cell 792e2a5402eSSrinivas Kandagatla * on success. The nvmem_cell will be freed by the automatically once the 793e2a5402eSSrinivas Kandagatla * device is freed. 794e2a5402eSSrinivas Kandagatla */ 795e2a5402eSSrinivas Kandagatla struct nvmem_device *devm_nvmem_device_get(struct device *dev, const char *id) 796e2a5402eSSrinivas Kandagatla { 797e2a5402eSSrinivas Kandagatla struct nvmem_device **ptr, *nvmem; 798e2a5402eSSrinivas Kandagatla 799e2a5402eSSrinivas Kandagatla ptr = devres_alloc(devm_nvmem_device_release, sizeof(*ptr), GFP_KERNEL); 800e2a5402eSSrinivas Kandagatla if (!ptr) 801e2a5402eSSrinivas Kandagatla return ERR_PTR(-ENOMEM); 802e2a5402eSSrinivas Kandagatla 803e2a5402eSSrinivas Kandagatla nvmem = nvmem_device_get(dev, id); 804e2a5402eSSrinivas Kandagatla if (!IS_ERR(nvmem)) { 805e2a5402eSSrinivas Kandagatla *ptr = nvmem; 806e2a5402eSSrinivas Kandagatla devres_add(dev, ptr); 807e2a5402eSSrinivas Kandagatla } else { 808e2a5402eSSrinivas Kandagatla devres_free(ptr); 809e2a5402eSSrinivas Kandagatla } 810e2a5402eSSrinivas Kandagatla 811e2a5402eSSrinivas Kandagatla return nvmem; 812e2a5402eSSrinivas Kandagatla } 813e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_device_get); 814e2a5402eSSrinivas Kandagatla 81569aba794SSrinivas Kandagatla static struct nvmem_cell *nvmem_cell_get_from_list(const char *cell_id) 81669aba794SSrinivas Kandagatla { 81769aba794SSrinivas Kandagatla struct nvmem_cell *cell = NULL; 81869aba794SSrinivas Kandagatla struct nvmem_device *nvmem; 81969aba794SSrinivas Kandagatla 82069aba794SSrinivas Kandagatla nvmem = __nvmem_device_get(NULL, &cell, cell_id); 82169aba794SSrinivas Kandagatla if (IS_ERR(nvmem)) 82269aba794SSrinivas Kandagatla return ERR_CAST(nvmem); 82369aba794SSrinivas Kandagatla 82469aba794SSrinivas Kandagatla return cell; 82569aba794SSrinivas Kandagatla } 82669aba794SSrinivas Kandagatla 827e701c67cSMasahiro Yamada #if IS_ENABLED(CONFIG_OF) 82869aba794SSrinivas Kandagatla /** 82969aba794SSrinivas Kandagatla * of_nvmem_cell_get() - Get a nvmem cell from given device node and cell id 83069aba794SSrinivas Kandagatla * 83129143268SVivek Gautam * @np: Device tree node that uses the nvmem cell. 832fd0c478cSVivek Gautam * @name: nvmem cell name from nvmem-cell-names property, or NULL 833fd0c478cSVivek Gautam * for the cell at index 0 (the lone cell with no accompanying 834fd0c478cSVivek Gautam * nvmem-cell-names property). 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 *of_nvmem_cell_get(struct device_node *np, 84169aba794SSrinivas Kandagatla const char *name) 84269aba794SSrinivas Kandagatla { 84369aba794SSrinivas Kandagatla struct device_node *cell_np, *nvmem_np; 84469aba794SSrinivas Kandagatla struct nvmem_cell *cell; 84569aba794SSrinivas Kandagatla struct nvmem_device *nvmem; 84669aba794SSrinivas Kandagatla const __be32 *addr; 847fd0c478cSVivek Gautam int rval, len; 848fd0c478cSVivek Gautam int index = 0; 84969aba794SSrinivas Kandagatla 850fd0c478cSVivek Gautam /* if cell name exists, find index to the name */ 851fd0c478cSVivek Gautam if (name) 85269aba794SSrinivas Kandagatla index = of_property_match_string(np, "nvmem-cell-names", name); 85369aba794SSrinivas Kandagatla 85469aba794SSrinivas Kandagatla cell_np = of_parse_phandle(np, "nvmem-cells", index); 85569aba794SSrinivas Kandagatla if (!cell_np) 85669aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 85769aba794SSrinivas Kandagatla 85869aba794SSrinivas Kandagatla nvmem_np = of_get_next_parent(cell_np); 85969aba794SSrinivas Kandagatla if (!nvmem_np) 86069aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 86169aba794SSrinivas Kandagatla 86269aba794SSrinivas Kandagatla nvmem = __nvmem_device_get(nvmem_np, NULL, NULL); 863aad8d097SMasahiro Yamada of_node_put(nvmem_np); 86469aba794SSrinivas Kandagatla if (IS_ERR(nvmem)) 86569aba794SSrinivas Kandagatla return ERR_CAST(nvmem); 86669aba794SSrinivas Kandagatla 86769aba794SSrinivas Kandagatla addr = of_get_property(cell_np, "reg", &len); 86869aba794SSrinivas Kandagatla if (!addr || (len < 2 * sizeof(u32))) { 8695f214ccdSRob Herring dev_err(&nvmem->dev, "nvmem: invalid reg on %pOF\n", 8705f214ccdSRob Herring cell_np); 87169aba794SSrinivas Kandagatla rval = -EINVAL; 87269aba794SSrinivas Kandagatla goto err_mem; 87369aba794SSrinivas Kandagatla } 87469aba794SSrinivas Kandagatla 87569aba794SSrinivas Kandagatla cell = kzalloc(sizeof(*cell), GFP_KERNEL); 87669aba794SSrinivas Kandagatla if (!cell) { 87769aba794SSrinivas Kandagatla rval = -ENOMEM; 87869aba794SSrinivas Kandagatla goto err_mem; 87969aba794SSrinivas Kandagatla } 88069aba794SSrinivas Kandagatla 88169aba794SSrinivas Kandagatla cell->nvmem = nvmem; 88269aba794SSrinivas Kandagatla cell->offset = be32_to_cpup(addr++); 88369aba794SSrinivas Kandagatla cell->bytes = be32_to_cpup(addr); 88469aba794SSrinivas Kandagatla cell->name = cell_np->name; 88569aba794SSrinivas Kandagatla 88669aba794SSrinivas Kandagatla addr = of_get_property(cell_np, "bits", &len); 88769aba794SSrinivas Kandagatla if (addr && len == (2 * sizeof(u32))) { 88869aba794SSrinivas Kandagatla cell->bit_offset = be32_to_cpup(addr++); 88969aba794SSrinivas Kandagatla cell->nbits = be32_to_cpup(addr); 89069aba794SSrinivas Kandagatla } 89169aba794SSrinivas Kandagatla 89269aba794SSrinivas Kandagatla if (cell->nbits) 89369aba794SSrinivas Kandagatla cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset, 89469aba794SSrinivas Kandagatla BITS_PER_BYTE); 89569aba794SSrinivas Kandagatla 89669aba794SSrinivas Kandagatla if (!IS_ALIGNED(cell->offset, nvmem->stride)) { 89769aba794SSrinivas Kandagatla dev_err(&nvmem->dev, 89869aba794SSrinivas Kandagatla "cell %s unaligned to nvmem stride %d\n", 89969aba794SSrinivas Kandagatla cell->name, nvmem->stride); 90069aba794SSrinivas Kandagatla rval = -EINVAL; 90169aba794SSrinivas Kandagatla goto err_sanity; 90269aba794SSrinivas Kandagatla } 90369aba794SSrinivas Kandagatla 90469aba794SSrinivas Kandagatla nvmem_cell_add(cell); 90569aba794SSrinivas Kandagatla 90669aba794SSrinivas Kandagatla return cell; 90769aba794SSrinivas Kandagatla 90869aba794SSrinivas Kandagatla err_sanity: 90969aba794SSrinivas Kandagatla kfree(cell); 91069aba794SSrinivas Kandagatla 91169aba794SSrinivas Kandagatla err_mem: 91269aba794SSrinivas Kandagatla __nvmem_device_put(nvmem); 91369aba794SSrinivas Kandagatla 91469aba794SSrinivas Kandagatla return ERR_PTR(rval); 91569aba794SSrinivas Kandagatla } 91669aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_nvmem_cell_get); 91769aba794SSrinivas Kandagatla #endif 91869aba794SSrinivas Kandagatla 91969aba794SSrinivas Kandagatla /** 92069aba794SSrinivas Kandagatla * nvmem_cell_get() - Get nvmem cell of device form a given cell name 92169aba794SSrinivas Kandagatla * 92229143268SVivek Gautam * @dev: Device that requests the nvmem cell. 92329143268SVivek Gautam * @cell_id: nvmem cell name to get. 92469aba794SSrinivas Kandagatla * 92569aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 92669aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 92769aba794SSrinivas Kandagatla * nvmem_cell_put(). 92869aba794SSrinivas Kandagatla */ 92969aba794SSrinivas Kandagatla struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *cell_id) 93069aba794SSrinivas Kandagatla { 93169aba794SSrinivas Kandagatla struct nvmem_cell *cell; 93269aba794SSrinivas Kandagatla 93369aba794SSrinivas Kandagatla if (dev->of_node) { /* try dt first */ 93469aba794SSrinivas Kandagatla cell = of_nvmem_cell_get(dev->of_node, cell_id); 93569aba794SSrinivas Kandagatla if (!IS_ERR(cell) || PTR_ERR(cell) == -EPROBE_DEFER) 93669aba794SSrinivas Kandagatla return cell; 93769aba794SSrinivas Kandagatla } 93869aba794SSrinivas Kandagatla 93969aba794SSrinivas Kandagatla return nvmem_cell_get_from_list(cell_id); 94069aba794SSrinivas Kandagatla } 94169aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_get); 94269aba794SSrinivas Kandagatla 94369aba794SSrinivas Kandagatla static void devm_nvmem_cell_release(struct device *dev, void *res) 94469aba794SSrinivas Kandagatla { 94569aba794SSrinivas Kandagatla nvmem_cell_put(*(struct nvmem_cell **)res); 94669aba794SSrinivas Kandagatla } 94769aba794SSrinivas Kandagatla 94869aba794SSrinivas Kandagatla /** 94969aba794SSrinivas Kandagatla * devm_nvmem_cell_get() - Get nvmem cell of device form a given id 95069aba794SSrinivas Kandagatla * 95129143268SVivek Gautam * @dev: Device that requests the nvmem cell. 95229143268SVivek Gautam * @id: nvmem cell name id to get. 95369aba794SSrinivas Kandagatla * 95469aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 95569aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 95669aba794SSrinivas Kandagatla * automatically once the device is freed. 95769aba794SSrinivas Kandagatla */ 95869aba794SSrinivas Kandagatla struct nvmem_cell *devm_nvmem_cell_get(struct device *dev, const char *id) 95969aba794SSrinivas Kandagatla { 96069aba794SSrinivas Kandagatla struct nvmem_cell **ptr, *cell; 96169aba794SSrinivas Kandagatla 96269aba794SSrinivas Kandagatla ptr = devres_alloc(devm_nvmem_cell_release, sizeof(*ptr), GFP_KERNEL); 96369aba794SSrinivas Kandagatla if (!ptr) 96469aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 96569aba794SSrinivas Kandagatla 96669aba794SSrinivas Kandagatla cell = nvmem_cell_get(dev, id); 96769aba794SSrinivas Kandagatla if (!IS_ERR(cell)) { 96869aba794SSrinivas Kandagatla *ptr = cell; 96969aba794SSrinivas Kandagatla devres_add(dev, ptr); 97069aba794SSrinivas Kandagatla } else { 97169aba794SSrinivas Kandagatla devres_free(ptr); 97269aba794SSrinivas Kandagatla } 97369aba794SSrinivas Kandagatla 97469aba794SSrinivas Kandagatla return cell; 97569aba794SSrinivas Kandagatla } 97669aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_cell_get); 97769aba794SSrinivas Kandagatla 97869aba794SSrinivas Kandagatla static int devm_nvmem_cell_match(struct device *dev, void *res, void *data) 97969aba794SSrinivas Kandagatla { 98069aba794SSrinivas Kandagatla struct nvmem_cell **c = res; 98169aba794SSrinivas Kandagatla 98269aba794SSrinivas Kandagatla if (WARN_ON(!c || !*c)) 98369aba794SSrinivas Kandagatla return 0; 98469aba794SSrinivas Kandagatla 98569aba794SSrinivas Kandagatla return *c == data; 98669aba794SSrinivas Kandagatla } 98769aba794SSrinivas Kandagatla 98869aba794SSrinivas Kandagatla /** 98969aba794SSrinivas Kandagatla * devm_nvmem_cell_put() - Release previously allocated nvmem cell 99069aba794SSrinivas Kandagatla * from devm_nvmem_cell_get. 99169aba794SSrinivas Kandagatla * 99229143268SVivek Gautam * @dev: Device that requests the nvmem cell. 99329143268SVivek Gautam * @cell: Previously allocated nvmem cell by devm_nvmem_cell_get(). 99469aba794SSrinivas Kandagatla */ 99569aba794SSrinivas Kandagatla void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell) 99669aba794SSrinivas Kandagatla { 99769aba794SSrinivas Kandagatla int ret; 99869aba794SSrinivas Kandagatla 99969aba794SSrinivas Kandagatla ret = devres_release(dev, devm_nvmem_cell_release, 100069aba794SSrinivas Kandagatla devm_nvmem_cell_match, cell); 100169aba794SSrinivas Kandagatla 100269aba794SSrinivas Kandagatla WARN_ON(ret); 100369aba794SSrinivas Kandagatla } 100469aba794SSrinivas Kandagatla EXPORT_SYMBOL(devm_nvmem_cell_put); 100569aba794SSrinivas Kandagatla 100669aba794SSrinivas Kandagatla /** 100769aba794SSrinivas Kandagatla * nvmem_cell_put() - Release previously allocated nvmem cell. 100869aba794SSrinivas Kandagatla * 100929143268SVivek Gautam * @cell: Previously allocated nvmem cell by nvmem_cell_get(). 101069aba794SSrinivas Kandagatla */ 101169aba794SSrinivas Kandagatla void nvmem_cell_put(struct nvmem_cell *cell) 101269aba794SSrinivas Kandagatla { 101369aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 101469aba794SSrinivas Kandagatla 101569aba794SSrinivas Kandagatla __nvmem_device_put(nvmem); 101669aba794SSrinivas Kandagatla nvmem_cell_drop(cell); 101769aba794SSrinivas Kandagatla } 101869aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_put); 101969aba794SSrinivas Kandagatla 1020f7c04f16SMasahiro Yamada static void nvmem_shift_read_buffer_in_place(struct nvmem_cell *cell, void *buf) 102169aba794SSrinivas Kandagatla { 102269aba794SSrinivas Kandagatla u8 *p, *b; 102369aba794SSrinivas Kandagatla int i, bit_offset = cell->bit_offset; 102469aba794SSrinivas Kandagatla 102569aba794SSrinivas Kandagatla p = b = buf; 102669aba794SSrinivas Kandagatla if (bit_offset) { 102769aba794SSrinivas Kandagatla /* First shift */ 102869aba794SSrinivas Kandagatla *b++ >>= bit_offset; 102969aba794SSrinivas Kandagatla 103069aba794SSrinivas Kandagatla /* setup rest of the bytes if any */ 103169aba794SSrinivas Kandagatla for (i = 1; i < cell->bytes; i++) { 103269aba794SSrinivas Kandagatla /* Get bits from next byte and shift them towards msb */ 103369aba794SSrinivas Kandagatla *p |= *b << (BITS_PER_BYTE - bit_offset); 103469aba794SSrinivas Kandagatla 103569aba794SSrinivas Kandagatla p = b; 103669aba794SSrinivas Kandagatla *b++ >>= bit_offset; 103769aba794SSrinivas Kandagatla } 103869aba794SSrinivas Kandagatla 103969aba794SSrinivas Kandagatla /* result fits in less bytes */ 104069aba794SSrinivas Kandagatla if (cell->bytes != DIV_ROUND_UP(cell->nbits, BITS_PER_BYTE)) 104169aba794SSrinivas Kandagatla *p-- = 0; 104269aba794SSrinivas Kandagatla } 104369aba794SSrinivas Kandagatla /* clear msb bits if any leftover in the last byte */ 104469aba794SSrinivas Kandagatla *p &= GENMASK((cell->nbits%BITS_PER_BYTE) - 1, 0); 104569aba794SSrinivas Kandagatla } 104669aba794SSrinivas Kandagatla 104769aba794SSrinivas Kandagatla static int __nvmem_cell_read(struct nvmem_device *nvmem, 104869aba794SSrinivas Kandagatla struct nvmem_cell *cell, 104969aba794SSrinivas Kandagatla void *buf, size_t *len) 105069aba794SSrinivas Kandagatla { 105169aba794SSrinivas Kandagatla int rc; 105269aba794SSrinivas Kandagatla 1053795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, cell->offset, buf, cell->bytes); 105469aba794SSrinivas Kandagatla 1055287980e4SArnd Bergmann if (rc) 105669aba794SSrinivas Kandagatla return rc; 105769aba794SSrinivas Kandagatla 105869aba794SSrinivas Kandagatla /* shift bits in-place */ 1059cbf854abSAxel Lin if (cell->bit_offset || cell->nbits) 106069aba794SSrinivas Kandagatla nvmem_shift_read_buffer_in_place(cell, buf); 106169aba794SSrinivas Kandagatla 10623b4a6877SVivek Gautam if (len) 106369aba794SSrinivas Kandagatla *len = cell->bytes; 106469aba794SSrinivas Kandagatla 106569aba794SSrinivas Kandagatla return 0; 106669aba794SSrinivas Kandagatla } 106769aba794SSrinivas Kandagatla 106869aba794SSrinivas Kandagatla /** 106969aba794SSrinivas Kandagatla * nvmem_cell_read() - Read a given nvmem cell 107069aba794SSrinivas Kandagatla * 107169aba794SSrinivas Kandagatla * @cell: nvmem cell to be read. 10723b4a6877SVivek Gautam * @len: pointer to length of cell which will be populated on successful read; 10733b4a6877SVivek Gautam * can be NULL. 107469aba794SSrinivas Kandagatla * 1075b577fafcSBrian Norris * Return: ERR_PTR() on error or a valid pointer to a buffer on success. The 1076b577fafcSBrian Norris * buffer should be freed by the consumer with a kfree(). 107769aba794SSrinivas Kandagatla */ 107869aba794SSrinivas Kandagatla void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len) 107969aba794SSrinivas Kandagatla { 108069aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 108169aba794SSrinivas Kandagatla u8 *buf; 108269aba794SSrinivas Kandagatla int rc; 108369aba794SSrinivas Kandagatla 1084795ddd18SSrinivas Kandagatla if (!nvmem) 108569aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 108669aba794SSrinivas Kandagatla 108769aba794SSrinivas Kandagatla buf = kzalloc(cell->bytes, GFP_KERNEL); 108869aba794SSrinivas Kandagatla if (!buf) 108969aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 109069aba794SSrinivas Kandagatla 109169aba794SSrinivas Kandagatla rc = __nvmem_cell_read(nvmem, cell, buf, len); 1092287980e4SArnd Bergmann if (rc) { 109369aba794SSrinivas Kandagatla kfree(buf); 109469aba794SSrinivas Kandagatla return ERR_PTR(rc); 109569aba794SSrinivas Kandagatla } 109669aba794SSrinivas Kandagatla 109769aba794SSrinivas Kandagatla return buf; 109869aba794SSrinivas Kandagatla } 109969aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_read); 110069aba794SSrinivas Kandagatla 1101f7c04f16SMasahiro Yamada static void *nvmem_cell_prepare_write_buffer(struct nvmem_cell *cell, 110269aba794SSrinivas Kandagatla u8 *_buf, int len) 110369aba794SSrinivas Kandagatla { 110469aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 110569aba794SSrinivas Kandagatla int i, rc, nbits, bit_offset = cell->bit_offset; 110669aba794SSrinivas Kandagatla u8 v, *p, *buf, *b, pbyte, pbits; 110769aba794SSrinivas Kandagatla 110869aba794SSrinivas Kandagatla nbits = cell->nbits; 110969aba794SSrinivas Kandagatla buf = kzalloc(cell->bytes, GFP_KERNEL); 111069aba794SSrinivas Kandagatla if (!buf) 111169aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 111269aba794SSrinivas Kandagatla 111369aba794SSrinivas Kandagatla memcpy(buf, _buf, len); 111469aba794SSrinivas Kandagatla p = b = buf; 111569aba794SSrinivas Kandagatla 111669aba794SSrinivas Kandagatla if (bit_offset) { 111769aba794SSrinivas Kandagatla pbyte = *b; 111869aba794SSrinivas Kandagatla *b <<= bit_offset; 111969aba794SSrinivas Kandagatla 112069aba794SSrinivas Kandagatla /* setup the first byte with lsb bits from nvmem */ 1121795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, cell->offset, &v, 1); 112269aba794SSrinivas Kandagatla *b++ |= GENMASK(bit_offset - 1, 0) & v; 112369aba794SSrinivas Kandagatla 112469aba794SSrinivas Kandagatla /* setup rest of the byte if any */ 112569aba794SSrinivas Kandagatla for (i = 1; i < cell->bytes; i++) { 112669aba794SSrinivas Kandagatla /* Get last byte bits and shift them towards lsb */ 112769aba794SSrinivas Kandagatla pbits = pbyte >> (BITS_PER_BYTE - 1 - bit_offset); 112869aba794SSrinivas Kandagatla pbyte = *b; 112969aba794SSrinivas Kandagatla p = b; 113069aba794SSrinivas Kandagatla *b <<= bit_offset; 113169aba794SSrinivas Kandagatla *b++ |= pbits; 113269aba794SSrinivas Kandagatla } 113369aba794SSrinivas Kandagatla } 113469aba794SSrinivas Kandagatla 113569aba794SSrinivas Kandagatla /* if it's not end on byte boundary */ 113669aba794SSrinivas Kandagatla if ((nbits + bit_offset) % BITS_PER_BYTE) { 113769aba794SSrinivas Kandagatla /* setup the last byte with msb bits from nvmem */ 1138795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, 113969aba794SSrinivas Kandagatla cell->offset + cell->bytes - 1, &v, 1); 114069aba794SSrinivas Kandagatla *p |= GENMASK(7, (nbits + bit_offset) % BITS_PER_BYTE) & v; 114169aba794SSrinivas Kandagatla 114269aba794SSrinivas Kandagatla } 114369aba794SSrinivas Kandagatla 114469aba794SSrinivas Kandagatla return buf; 114569aba794SSrinivas Kandagatla } 114669aba794SSrinivas Kandagatla 114769aba794SSrinivas Kandagatla /** 114869aba794SSrinivas Kandagatla * nvmem_cell_write() - Write to a given nvmem cell 114969aba794SSrinivas Kandagatla * 115069aba794SSrinivas Kandagatla * @cell: nvmem cell to be written. 115169aba794SSrinivas Kandagatla * @buf: Buffer to be written. 115269aba794SSrinivas Kandagatla * @len: length of buffer to be written to nvmem cell. 115369aba794SSrinivas Kandagatla * 115469aba794SSrinivas Kandagatla * Return: length of bytes written or negative on failure. 115569aba794SSrinivas Kandagatla */ 115669aba794SSrinivas Kandagatla int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len) 115769aba794SSrinivas Kandagatla { 115869aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 115969aba794SSrinivas Kandagatla int rc; 116069aba794SSrinivas Kandagatla 1161795ddd18SSrinivas Kandagatla if (!nvmem || nvmem->read_only || 116269aba794SSrinivas Kandagatla (cell->bit_offset == 0 && len != cell->bytes)) 116369aba794SSrinivas Kandagatla return -EINVAL; 116469aba794SSrinivas Kandagatla 116569aba794SSrinivas Kandagatla if (cell->bit_offset || cell->nbits) { 116669aba794SSrinivas Kandagatla buf = nvmem_cell_prepare_write_buffer(cell, buf, len); 116769aba794SSrinivas Kandagatla if (IS_ERR(buf)) 116869aba794SSrinivas Kandagatla return PTR_ERR(buf); 116969aba794SSrinivas Kandagatla } 117069aba794SSrinivas Kandagatla 1171795ddd18SSrinivas Kandagatla rc = nvmem_reg_write(nvmem, cell->offset, buf, cell->bytes); 117269aba794SSrinivas Kandagatla 117369aba794SSrinivas Kandagatla /* free the tmp buffer */ 1174ace22170SAxel Lin if (cell->bit_offset || cell->nbits) 117569aba794SSrinivas Kandagatla kfree(buf); 117669aba794SSrinivas Kandagatla 1177287980e4SArnd Bergmann if (rc) 117869aba794SSrinivas Kandagatla return rc; 117969aba794SSrinivas Kandagatla 118069aba794SSrinivas Kandagatla return len; 118169aba794SSrinivas Kandagatla } 118269aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_write); 118369aba794SSrinivas Kandagatla 1184e2a5402eSSrinivas Kandagatla /** 1185d026d70aSLeonard Crestez * nvmem_cell_read_u32() - Read a cell value as an u32 1186d026d70aSLeonard Crestez * 1187d026d70aSLeonard Crestez * @dev: Device that requests the nvmem cell. 1188d026d70aSLeonard Crestez * @cell_id: Name of nvmem cell to read. 1189d026d70aSLeonard Crestez * @val: pointer to output value. 1190d026d70aSLeonard Crestez * 1191d026d70aSLeonard Crestez * Return: 0 on success or negative errno. 1192d026d70aSLeonard Crestez */ 1193d026d70aSLeonard Crestez int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val) 1194d026d70aSLeonard Crestez { 1195d026d70aSLeonard Crestez struct nvmem_cell *cell; 1196d026d70aSLeonard Crestez void *buf; 1197d026d70aSLeonard Crestez size_t len; 1198d026d70aSLeonard Crestez 1199d026d70aSLeonard Crestez cell = nvmem_cell_get(dev, cell_id); 1200d026d70aSLeonard Crestez if (IS_ERR(cell)) 1201d026d70aSLeonard Crestez return PTR_ERR(cell); 1202d026d70aSLeonard Crestez 1203d026d70aSLeonard Crestez buf = nvmem_cell_read(cell, &len); 1204d026d70aSLeonard Crestez if (IS_ERR(buf)) { 1205d026d70aSLeonard Crestez nvmem_cell_put(cell); 1206d026d70aSLeonard Crestez return PTR_ERR(buf); 1207d026d70aSLeonard Crestez } 1208d026d70aSLeonard Crestez if (len != sizeof(*val)) { 1209d026d70aSLeonard Crestez kfree(buf); 1210d026d70aSLeonard Crestez nvmem_cell_put(cell); 1211d026d70aSLeonard Crestez return -EINVAL; 1212d026d70aSLeonard Crestez } 1213d026d70aSLeonard Crestez memcpy(val, buf, sizeof(*val)); 1214d026d70aSLeonard Crestez 1215d026d70aSLeonard Crestez kfree(buf); 1216d026d70aSLeonard Crestez nvmem_cell_put(cell); 1217d026d70aSLeonard Crestez return 0; 1218d026d70aSLeonard Crestez } 1219d026d70aSLeonard Crestez EXPORT_SYMBOL_GPL(nvmem_cell_read_u32); 1220d026d70aSLeonard Crestez 1221d026d70aSLeonard Crestez /** 1222e2a5402eSSrinivas Kandagatla * nvmem_device_cell_read() - Read a given nvmem device and cell 1223e2a5402eSSrinivas Kandagatla * 1224e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to read from. 1225e2a5402eSSrinivas Kandagatla * @info: nvmem cell info to be read. 1226e2a5402eSSrinivas Kandagatla * @buf: buffer pointer which will be populated on successful read. 1227e2a5402eSSrinivas Kandagatla * 1228e2a5402eSSrinivas Kandagatla * Return: length of successful bytes read on success and negative 1229e2a5402eSSrinivas Kandagatla * error code on error. 1230e2a5402eSSrinivas Kandagatla */ 1231e2a5402eSSrinivas Kandagatla ssize_t nvmem_device_cell_read(struct nvmem_device *nvmem, 1232e2a5402eSSrinivas Kandagatla struct nvmem_cell_info *info, void *buf) 1233e2a5402eSSrinivas Kandagatla { 1234e2a5402eSSrinivas Kandagatla struct nvmem_cell cell; 1235e2a5402eSSrinivas Kandagatla int rc; 1236e2a5402eSSrinivas Kandagatla ssize_t len; 1237e2a5402eSSrinivas Kandagatla 1238795ddd18SSrinivas Kandagatla if (!nvmem) 1239e2a5402eSSrinivas Kandagatla return -EINVAL; 1240e2a5402eSSrinivas Kandagatla 1241e2a5402eSSrinivas Kandagatla rc = nvmem_cell_info_to_nvmem_cell(nvmem, info, &cell); 1242287980e4SArnd Bergmann if (rc) 1243e2a5402eSSrinivas Kandagatla return rc; 1244e2a5402eSSrinivas Kandagatla 1245e2a5402eSSrinivas Kandagatla rc = __nvmem_cell_read(nvmem, &cell, buf, &len); 1246287980e4SArnd Bergmann if (rc) 1247e2a5402eSSrinivas Kandagatla return rc; 1248e2a5402eSSrinivas Kandagatla 1249e2a5402eSSrinivas Kandagatla return len; 1250e2a5402eSSrinivas Kandagatla } 1251e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_cell_read); 1252e2a5402eSSrinivas Kandagatla 1253e2a5402eSSrinivas Kandagatla /** 1254e2a5402eSSrinivas Kandagatla * nvmem_device_cell_write() - Write cell to a given nvmem device 1255e2a5402eSSrinivas Kandagatla * 1256e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to be written to. 125729143268SVivek Gautam * @info: nvmem cell info to be written. 1258e2a5402eSSrinivas Kandagatla * @buf: buffer to be written to cell. 1259e2a5402eSSrinivas Kandagatla * 1260e2a5402eSSrinivas Kandagatla * Return: length of bytes written or negative error code on failure. 1261e2a5402eSSrinivas Kandagatla * */ 1262e2a5402eSSrinivas Kandagatla int nvmem_device_cell_write(struct nvmem_device *nvmem, 1263e2a5402eSSrinivas Kandagatla struct nvmem_cell_info *info, void *buf) 1264e2a5402eSSrinivas Kandagatla { 1265e2a5402eSSrinivas Kandagatla struct nvmem_cell cell; 1266e2a5402eSSrinivas Kandagatla int rc; 1267e2a5402eSSrinivas Kandagatla 1268795ddd18SSrinivas Kandagatla if (!nvmem) 1269e2a5402eSSrinivas Kandagatla return -EINVAL; 1270e2a5402eSSrinivas Kandagatla 1271e2a5402eSSrinivas Kandagatla rc = nvmem_cell_info_to_nvmem_cell(nvmem, info, &cell); 1272287980e4SArnd Bergmann if (rc) 1273e2a5402eSSrinivas Kandagatla return rc; 1274e2a5402eSSrinivas Kandagatla 1275e2a5402eSSrinivas Kandagatla return nvmem_cell_write(&cell, buf, cell.bytes); 1276e2a5402eSSrinivas Kandagatla } 1277e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_cell_write); 1278e2a5402eSSrinivas Kandagatla 1279e2a5402eSSrinivas Kandagatla /** 1280e2a5402eSSrinivas Kandagatla * nvmem_device_read() - Read from a given nvmem device 1281e2a5402eSSrinivas Kandagatla * 1282e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to read from. 1283e2a5402eSSrinivas Kandagatla * @offset: offset in nvmem device. 1284e2a5402eSSrinivas Kandagatla * @bytes: number of bytes to read. 1285e2a5402eSSrinivas Kandagatla * @buf: buffer pointer which will be populated on successful read. 1286e2a5402eSSrinivas Kandagatla * 1287e2a5402eSSrinivas Kandagatla * Return: length of successful bytes read on success and negative 1288e2a5402eSSrinivas Kandagatla * error code on error. 1289e2a5402eSSrinivas Kandagatla */ 1290e2a5402eSSrinivas Kandagatla int nvmem_device_read(struct nvmem_device *nvmem, 1291e2a5402eSSrinivas Kandagatla unsigned int offset, 1292e2a5402eSSrinivas Kandagatla size_t bytes, void *buf) 1293e2a5402eSSrinivas Kandagatla { 1294e2a5402eSSrinivas Kandagatla int rc; 1295e2a5402eSSrinivas Kandagatla 1296795ddd18SSrinivas Kandagatla if (!nvmem) 1297e2a5402eSSrinivas Kandagatla return -EINVAL; 1298e2a5402eSSrinivas Kandagatla 1299795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, offset, buf, bytes); 1300e2a5402eSSrinivas Kandagatla 1301287980e4SArnd Bergmann if (rc) 1302e2a5402eSSrinivas Kandagatla return rc; 1303e2a5402eSSrinivas Kandagatla 1304e2a5402eSSrinivas Kandagatla return bytes; 1305e2a5402eSSrinivas Kandagatla } 1306e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_read); 1307e2a5402eSSrinivas Kandagatla 1308e2a5402eSSrinivas Kandagatla /** 1309e2a5402eSSrinivas Kandagatla * nvmem_device_write() - Write cell to a given nvmem device 1310e2a5402eSSrinivas Kandagatla * 1311e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to be written to. 1312e2a5402eSSrinivas Kandagatla * @offset: offset in nvmem device. 1313e2a5402eSSrinivas Kandagatla * @bytes: number of bytes to write. 1314e2a5402eSSrinivas Kandagatla * @buf: buffer to be written. 1315e2a5402eSSrinivas Kandagatla * 1316e2a5402eSSrinivas Kandagatla * Return: length of bytes written or negative error code on failure. 1317e2a5402eSSrinivas Kandagatla * */ 1318e2a5402eSSrinivas Kandagatla int nvmem_device_write(struct nvmem_device *nvmem, 1319e2a5402eSSrinivas Kandagatla unsigned int offset, 1320e2a5402eSSrinivas Kandagatla size_t bytes, void *buf) 1321e2a5402eSSrinivas Kandagatla { 1322e2a5402eSSrinivas Kandagatla int rc; 1323e2a5402eSSrinivas Kandagatla 1324795ddd18SSrinivas Kandagatla if (!nvmem) 1325e2a5402eSSrinivas Kandagatla return -EINVAL; 1326e2a5402eSSrinivas Kandagatla 1327795ddd18SSrinivas Kandagatla rc = nvmem_reg_write(nvmem, offset, buf, bytes); 1328e2a5402eSSrinivas Kandagatla 1329287980e4SArnd Bergmann if (rc) 1330e2a5402eSSrinivas Kandagatla return rc; 1331e2a5402eSSrinivas Kandagatla 1332e2a5402eSSrinivas Kandagatla 1333e2a5402eSSrinivas Kandagatla return bytes; 1334e2a5402eSSrinivas Kandagatla } 1335e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_write); 1336e2a5402eSSrinivas Kandagatla 1337eace75cfSSrinivas Kandagatla static int __init nvmem_init(void) 1338eace75cfSSrinivas Kandagatla { 1339eace75cfSSrinivas Kandagatla return bus_register(&nvmem_bus_type); 1340eace75cfSSrinivas Kandagatla } 1341eace75cfSSrinivas Kandagatla 1342eace75cfSSrinivas Kandagatla static void __exit nvmem_exit(void) 1343eace75cfSSrinivas Kandagatla { 1344eace75cfSSrinivas Kandagatla bus_unregister(&nvmem_bus_type); 1345eace75cfSSrinivas Kandagatla } 1346eace75cfSSrinivas Kandagatla 1347eace75cfSSrinivas Kandagatla subsys_initcall(nvmem_init); 1348eace75cfSSrinivas Kandagatla module_exit(nvmem_exit); 1349eace75cfSSrinivas Kandagatla 1350eace75cfSSrinivas Kandagatla MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org"); 1351eace75cfSSrinivas Kandagatla MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com"); 1352eace75cfSSrinivas Kandagatla MODULE_DESCRIPTION("nvmem Driver Core"); 1353eace75cfSSrinivas Kandagatla MODULE_LICENSE("GPL v2"); 1354