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 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 356eace75cfSSrinivas Kandagatla static int nvmem_add_cells(struct nvmem_device *nvmem, 357eace75cfSSrinivas Kandagatla const struct nvmem_config *cfg) 358eace75cfSSrinivas Kandagatla { 359eace75cfSSrinivas Kandagatla struct nvmem_cell **cells; 360eace75cfSSrinivas Kandagatla const struct nvmem_cell_info *info = cfg->cells; 361eace75cfSSrinivas Kandagatla int i, rval; 362eace75cfSSrinivas Kandagatla 363eace75cfSSrinivas Kandagatla cells = kcalloc(cfg->ncells, sizeof(*cells), GFP_KERNEL); 364eace75cfSSrinivas Kandagatla if (!cells) 365eace75cfSSrinivas Kandagatla return -ENOMEM; 366eace75cfSSrinivas Kandagatla 367eace75cfSSrinivas Kandagatla for (i = 0; i < cfg->ncells; i++) { 368eace75cfSSrinivas Kandagatla cells[i] = kzalloc(sizeof(**cells), GFP_KERNEL); 369eace75cfSSrinivas Kandagatla if (!cells[i]) { 370eace75cfSSrinivas Kandagatla rval = -ENOMEM; 371eace75cfSSrinivas Kandagatla goto err; 372eace75cfSSrinivas Kandagatla } 373eace75cfSSrinivas Kandagatla 374eace75cfSSrinivas Kandagatla rval = nvmem_cell_info_to_nvmem_cell(nvmem, &info[i], cells[i]); 375287980e4SArnd Bergmann if (rval) { 376eace75cfSSrinivas Kandagatla kfree(cells[i]); 377eace75cfSSrinivas Kandagatla goto err; 378eace75cfSSrinivas Kandagatla } 379eace75cfSSrinivas Kandagatla 380eace75cfSSrinivas Kandagatla nvmem_cell_add(cells[i]); 381eace75cfSSrinivas Kandagatla } 382eace75cfSSrinivas Kandagatla 383eace75cfSSrinivas Kandagatla nvmem->ncells = cfg->ncells; 384eace75cfSSrinivas Kandagatla /* remove tmp array */ 385eace75cfSSrinivas Kandagatla kfree(cells); 386eace75cfSSrinivas Kandagatla 387eace75cfSSrinivas Kandagatla return 0; 388eace75cfSSrinivas Kandagatla err: 389dfdf1414SRasmus Villemoes while (i--) 390eace75cfSSrinivas Kandagatla nvmem_cell_drop(cells[i]); 391eace75cfSSrinivas Kandagatla 392dfdf1414SRasmus Villemoes kfree(cells); 393dfdf1414SRasmus Villemoes 394eace75cfSSrinivas Kandagatla return rval; 395eace75cfSSrinivas Kandagatla } 396eace75cfSSrinivas Kandagatla 397b6c217abSAndrew Lunn /* 398b6c217abSAndrew Lunn * nvmem_setup_compat() - Create an additional binary entry in 399b6c217abSAndrew Lunn * drivers sys directory, to be backwards compatible with the older 400b6c217abSAndrew Lunn * drivers/misc/eeprom drivers. 401b6c217abSAndrew Lunn */ 402b6c217abSAndrew Lunn static int nvmem_setup_compat(struct nvmem_device *nvmem, 403b6c217abSAndrew Lunn const struct nvmem_config *config) 404b6c217abSAndrew Lunn { 405b6c217abSAndrew Lunn int rval; 406b6c217abSAndrew Lunn 407b6c217abSAndrew Lunn if (!config->base_dev) 408b6c217abSAndrew Lunn return -EINVAL; 409b6c217abSAndrew Lunn 410b6c217abSAndrew Lunn if (nvmem->read_only) 411b6c217abSAndrew Lunn nvmem->eeprom = bin_attr_ro_root_nvmem; 412b6c217abSAndrew Lunn else 413b6c217abSAndrew Lunn nvmem->eeprom = bin_attr_rw_root_nvmem; 414b6c217abSAndrew Lunn nvmem->eeprom.attr.name = "eeprom"; 415b6c217abSAndrew Lunn nvmem->eeprom.size = nvmem->size; 416b6c217abSAndrew Lunn #ifdef CONFIG_DEBUG_LOCK_ALLOC 417b6c217abSAndrew Lunn nvmem->eeprom.attr.key = &eeprom_lock_key; 418b6c217abSAndrew Lunn #endif 419b6c217abSAndrew Lunn nvmem->eeprom.private = &nvmem->dev; 420b6c217abSAndrew Lunn nvmem->base_dev = config->base_dev; 421b6c217abSAndrew Lunn 422b6c217abSAndrew Lunn rval = device_create_bin_file(nvmem->base_dev, &nvmem->eeprom); 423b6c217abSAndrew Lunn if (rval) { 424b6c217abSAndrew Lunn dev_err(&nvmem->dev, 425b6c217abSAndrew Lunn "Failed to create eeprom binary file %d\n", rval); 426b6c217abSAndrew Lunn return rval; 427b6c217abSAndrew Lunn } 428b6c217abSAndrew Lunn 429b6c217abSAndrew Lunn nvmem->flags |= FLAG_COMPAT; 430b6c217abSAndrew Lunn 431b6c217abSAndrew Lunn return 0; 432b6c217abSAndrew Lunn } 433b6c217abSAndrew Lunn 434eace75cfSSrinivas Kandagatla /** 435eace75cfSSrinivas Kandagatla * nvmem_register() - Register a nvmem device for given nvmem_config. 436eace75cfSSrinivas Kandagatla * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem 437eace75cfSSrinivas Kandagatla * 438eace75cfSSrinivas Kandagatla * @config: nvmem device configuration with which nvmem device is created. 439eace75cfSSrinivas Kandagatla * 440eace75cfSSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device 441eace75cfSSrinivas Kandagatla * on success. 442eace75cfSSrinivas Kandagatla */ 443eace75cfSSrinivas Kandagatla 444eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem_register(const struct nvmem_config *config) 445eace75cfSSrinivas Kandagatla { 446eace75cfSSrinivas Kandagatla struct nvmem_device *nvmem; 447eace75cfSSrinivas Kandagatla struct device_node *np; 448eace75cfSSrinivas Kandagatla int rval; 449eace75cfSSrinivas Kandagatla 450eace75cfSSrinivas Kandagatla if (!config->dev) 451eace75cfSSrinivas Kandagatla return ERR_PTR(-EINVAL); 452eace75cfSSrinivas Kandagatla 453eace75cfSSrinivas Kandagatla nvmem = kzalloc(sizeof(*nvmem), GFP_KERNEL); 454eace75cfSSrinivas Kandagatla if (!nvmem) 455eace75cfSSrinivas Kandagatla return ERR_PTR(-ENOMEM); 456eace75cfSSrinivas Kandagatla 457eace75cfSSrinivas Kandagatla rval = ida_simple_get(&nvmem_ida, 0, 0, GFP_KERNEL); 458eace75cfSSrinivas Kandagatla if (rval < 0) { 459eace75cfSSrinivas Kandagatla kfree(nvmem); 460eace75cfSSrinivas Kandagatla return ERR_PTR(rval); 461eace75cfSSrinivas Kandagatla } 462eace75cfSSrinivas Kandagatla 463eace75cfSSrinivas Kandagatla nvmem->id = rval; 464eace75cfSSrinivas Kandagatla nvmem->owner = config->owner; 465795ddd18SSrinivas Kandagatla nvmem->stride = config->stride; 466795ddd18SSrinivas Kandagatla nvmem->word_size = config->word_size; 467795ddd18SSrinivas Kandagatla nvmem->size = config->size; 468eace75cfSSrinivas Kandagatla nvmem->dev.type = &nvmem_provider_type; 469eace75cfSSrinivas Kandagatla nvmem->dev.bus = &nvmem_bus_type; 470eace75cfSSrinivas Kandagatla nvmem->dev.parent = config->dev; 471795ddd18SSrinivas Kandagatla nvmem->priv = config->priv; 472795ddd18SSrinivas Kandagatla nvmem->reg_read = config->reg_read; 473795ddd18SSrinivas Kandagatla nvmem->reg_write = config->reg_write; 474eace75cfSSrinivas Kandagatla np = config->dev->of_node; 475eace75cfSSrinivas Kandagatla nvmem->dev.of_node = np; 476eace75cfSSrinivas Kandagatla dev_set_name(&nvmem->dev, "%s%d", 4775253193dSAban Bedel config->name ? : "nvmem", 4785253193dSAban Bedel config->name ? config->id : nvmem->id); 479eace75cfSSrinivas Kandagatla 480eace75cfSSrinivas Kandagatla nvmem->read_only = of_property_read_bool(np, "read-only") | 481eace75cfSSrinivas Kandagatla config->read_only; 482eace75cfSSrinivas Kandagatla 483811b0d65SAndrew Lunn if (config->root_only) 484811b0d65SAndrew Lunn nvmem->dev.groups = nvmem->read_only ? 485811b0d65SAndrew Lunn nvmem_ro_root_dev_groups : 486811b0d65SAndrew Lunn nvmem_rw_root_dev_groups; 487811b0d65SAndrew Lunn else 488811b0d65SAndrew Lunn nvmem->dev.groups = nvmem->read_only ? 489811b0d65SAndrew Lunn nvmem_ro_dev_groups : 490eace75cfSSrinivas Kandagatla nvmem_rw_dev_groups; 491eace75cfSSrinivas Kandagatla 492eace75cfSSrinivas Kandagatla device_initialize(&nvmem->dev); 493eace75cfSSrinivas Kandagatla 494eace75cfSSrinivas Kandagatla dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name); 495eace75cfSSrinivas Kandagatla 496eace75cfSSrinivas Kandagatla rval = device_add(&nvmem->dev); 497b6c217abSAndrew Lunn if (rval) 4983360acdfSJohan Hovold goto err_put_device; 499b6c217abSAndrew Lunn 500b6c217abSAndrew Lunn if (config->compat) { 501b6c217abSAndrew Lunn rval = nvmem_setup_compat(nvmem, config); 502b6c217abSAndrew Lunn if (rval) 5033360acdfSJohan Hovold goto err_device_del; 504eace75cfSSrinivas Kandagatla } 505eace75cfSSrinivas Kandagatla 506eace75cfSSrinivas Kandagatla if (config->cells) 507eace75cfSSrinivas Kandagatla nvmem_add_cells(nvmem, config); 508eace75cfSSrinivas Kandagatla 509eace75cfSSrinivas Kandagatla return nvmem; 5103360acdfSJohan Hovold 5113360acdfSJohan Hovold err_device_del: 5123360acdfSJohan Hovold device_del(&nvmem->dev); 5133360acdfSJohan Hovold err_put_device: 5143360acdfSJohan Hovold put_device(&nvmem->dev); 5153360acdfSJohan Hovold 516b6c217abSAndrew Lunn return ERR_PTR(rval); 517eace75cfSSrinivas Kandagatla } 518eace75cfSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_register); 519eace75cfSSrinivas Kandagatla 520eace75cfSSrinivas Kandagatla /** 521eace75cfSSrinivas Kandagatla * nvmem_unregister() - Unregister previously registered nvmem device 522eace75cfSSrinivas Kandagatla * 523eace75cfSSrinivas Kandagatla * @nvmem: Pointer to previously registered nvmem device. 524eace75cfSSrinivas Kandagatla * 525eace75cfSSrinivas Kandagatla * Return: Will be an negative on error or a zero on success. 526eace75cfSSrinivas Kandagatla */ 527eace75cfSSrinivas Kandagatla int nvmem_unregister(struct nvmem_device *nvmem) 528eace75cfSSrinivas Kandagatla { 52969aba794SSrinivas Kandagatla mutex_lock(&nvmem_mutex); 53069aba794SSrinivas Kandagatla if (nvmem->users) { 53169aba794SSrinivas Kandagatla mutex_unlock(&nvmem_mutex); 532eace75cfSSrinivas Kandagatla return -EBUSY; 53369aba794SSrinivas Kandagatla } 53469aba794SSrinivas Kandagatla mutex_unlock(&nvmem_mutex); 535eace75cfSSrinivas Kandagatla 536b6c217abSAndrew Lunn if (nvmem->flags & FLAG_COMPAT) 537b6c217abSAndrew Lunn device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); 538b6c217abSAndrew Lunn 539eace75cfSSrinivas Kandagatla nvmem_device_remove_all_cells(nvmem); 540eace75cfSSrinivas Kandagatla device_del(&nvmem->dev); 54179fbf046SAndrey Smirnov put_device(&nvmem->dev); 542eace75cfSSrinivas Kandagatla 543eace75cfSSrinivas Kandagatla return 0; 544eace75cfSSrinivas Kandagatla } 545eace75cfSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_unregister); 546eace75cfSSrinivas Kandagatla 54769aba794SSrinivas Kandagatla static struct nvmem_device *__nvmem_device_get(struct device_node *np, 54869aba794SSrinivas Kandagatla struct nvmem_cell **cellp, 54969aba794SSrinivas Kandagatla const char *cell_id) 55069aba794SSrinivas Kandagatla { 55169aba794SSrinivas Kandagatla struct nvmem_device *nvmem = NULL; 55269aba794SSrinivas Kandagatla 55369aba794SSrinivas Kandagatla mutex_lock(&nvmem_mutex); 55469aba794SSrinivas Kandagatla 55569aba794SSrinivas Kandagatla if (np) { 55669aba794SSrinivas Kandagatla nvmem = of_nvmem_find(np); 55769aba794SSrinivas Kandagatla if (!nvmem) { 55869aba794SSrinivas Kandagatla mutex_unlock(&nvmem_mutex); 55969aba794SSrinivas Kandagatla return ERR_PTR(-EPROBE_DEFER); 56069aba794SSrinivas Kandagatla } 56169aba794SSrinivas Kandagatla } else { 56269aba794SSrinivas Kandagatla struct nvmem_cell *cell = nvmem_find_cell(cell_id); 56369aba794SSrinivas Kandagatla 56469aba794SSrinivas Kandagatla if (cell) { 56569aba794SSrinivas Kandagatla nvmem = cell->nvmem; 56669aba794SSrinivas Kandagatla *cellp = cell; 56769aba794SSrinivas Kandagatla } 56869aba794SSrinivas Kandagatla 56969aba794SSrinivas Kandagatla if (!nvmem) { 57069aba794SSrinivas Kandagatla mutex_unlock(&nvmem_mutex); 57169aba794SSrinivas Kandagatla return ERR_PTR(-ENOENT); 57269aba794SSrinivas Kandagatla } 57369aba794SSrinivas Kandagatla } 57469aba794SSrinivas Kandagatla 57569aba794SSrinivas Kandagatla nvmem->users++; 57669aba794SSrinivas Kandagatla mutex_unlock(&nvmem_mutex); 57769aba794SSrinivas Kandagatla 57869aba794SSrinivas Kandagatla if (!try_module_get(nvmem->owner)) { 57969aba794SSrinivas Kandagatla dev_err(&nvmem->dev, 58069aba794SSrinivas Kandagatla "could not increase module refcount for cell %s\n", 58169aba794SSrinivas Kandagatla nvmem->name); 58269aba794SSrinivas Kandagatla 58369aba794SSrinivas Kandagatla mutex_lock(&nvmem_mutex); 58469aba794SSrinivas Kandagatla nvmem->users--; 58569aba794SSrinivas Kandagatla mutex_unlock(&nvmem_mutex); 58669aba794SSrinivas Kandagatla 58769aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 58869aba794SSrinivas Kandagatla } 58969aba794SSrinivas Kandagatla 59069aba794SSrinivas Kandagatla return nvmem; 59169aba794SSrinivas Kandagatla } 59269aba794SSrinivas Kandagatla 59369aba794SSrinivas Kandagatla static void __nvmem_device_put(struct nvmem_device *nvmem) 59469aba794SSrinivas Kandagatla { 59569aba794SSrinivas Kandagatla module_put(nvmem->owner); 59669aba794SSrinivas Kandagatla mutex_lock(&nvmem_mutex); 59769aba794SSrinivas Kandagatla nvmem->users--; 59869aba794SSrinivas Kandagatla mutex_unlock(&nvmem_mutex); 59969aba794SSrinivas Kandagatla } 60069aba794SSrinivas Kandagatla 601e2a5402eSSrinivas Kandagatla static int nvmem_match(struct device *dev, void *data) 602e2a5402eSSrinivas Kandagatla { 603e2a5402eSSrinivas Kandagatla return !strcmp(dev_name(dev), data); 604e2a5402eSSrinivas Kandagatla } 605e2a5402eSSrinivas Kandagatla 606e2a5402eSSrinivas Kandagatla static struct nvmem_device *nvmem_find(const char *name) 607e2a5402eSSrinivas Kandagatla { 608e2a5402eSSrinivas Kandagatla struct device *d; 609e2a5402eSSrinivas Kandagatla 610e2a5402eSSrinivas Kandagatla d = bus_find_device(&nvmem_bus_type, NULL, (void *)name, nvmem_match); 611e2a5402eSSrinivas Kandagatla 612e2a5402eSSrinivas Kandagatla if (!d) 613e2a5402eSSrinivas Kandagatla return NULL; 614e2a5402eSSrinivas Kandagatla 615e2a5402eSSrinivas Kandagatla return to_nvmem_device(d); 616e2a5402eSSrinivas Kandagatla } 617e2a5402eSSrinivas Kandagatla 618*e701c67cSMasahiro Yamada #if IS_ENABLED(CONFIG_OF) 619e2a5402eSSrinivas Kandagatla /** 620e2a5402eSSrinivas Kandagatla * of_nvmem_device_get() - Get nvmem device from a given id 621e2a5402eSSrinivas Kandagatla * 62229143268SVivek Gautam * @np: Device tree node that uses the nvmem device. 623e2a5402eSSrinivas Kandagatla * @id: nvmem name from nvmem-names property. 624e2a5402eSSrinivas Kandagatla * 625e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device 626e2a5402eSSrinivas Kandagatla * on success. 627e2a5402eSSrinivas Kandagatla */ 628e2a5402eSSrinivas Kandagatla struct nvmem_device *of_nvmem_device_get(struct device_node *np, const char *id) 629e2a5402eSSrinivas Kandagatla { 630e2a5402eSSrinivas Kandagatla 631e2a5402eSSrinivas Kandagatla struct device_node *nvmem_np; 632e2a5402eSSrinivas Kandagatla int index; 633e2a5402eSSrinivas Kandagatla 634e2a5402eSSrinivas Kandagatla index = of_property_match_string(np, "nvmem-names", id); 635e2a5402eSSrinivas Kandagatla 636e2a5402eSSrinivas Kandagatla nvmem_np = of_parse_phandle(np, "nvmem", index); 637e2a5402eSSrinivas Kandagatla if (!nvmem_np) 638e2a5402eSSrinivas Kandagatla return ERR_PTR(-EINVAL); 639e2a5402eSSrinivas Kandagatla 640e2a5402eSSrinivas Kandagatla return __nvmem_device_get(nvmem_np, NULL, NULL); 641e2a5402eSSrinivas Kandagatla } 642e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_nvmem_device_get); 643e2a5402eSSrinivas Kandagatla #endif 644e2a5402eSSrinivas Kandagatla 645e2a5402eSSrinivas Kandagatla /** 646e2a5402eSSrinivas Kandagatla * nvmem_device_get() - Get nvmem device from a given id 647e2a5402eSSrinivas Kandagatla * 64829143268SVivek Gautam * @dev: Device that uses the nvmem device. 64929143268SVivek Gautam * @dev_name: name of the requested nvmem device. 650e2a5402eSSrinivas Kandagatla * 651e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device 652e2a5402eSSrinivas Kandagatla * on success. 653e2a5402eSSrinivas Kandagatla */ 654e2a5402eSSrinivas Kandagatla struct nvmem_device *nvmem_device_get(struct device *dev, const char *dev_name) 655e2a5402eSSrinivas Kandagatla { 656e2a5402eSSrinivas Kandagatla if (dev->of_node) { /* try dt first */ 657e2a5402eSSrinivas Kandagatla struct nvmem_device *nvmem; 658e2a5402eSSrinivas Kandagatla 659e2a5402eSSrinivas Kandagatla nvmem = of_nvmem_device_get(dev->of_node, dev_name); 660e2a5402eSSrinivas Kandagatla 661e2a5402eSSrinivas Kandagatla if (!IS_ERR(nvmem) || PTR_ERR(nvmem) == -EPROBE_DEFER) 662e2a5402eSSrinivas Kandagatla return nvmem; 663e2a5402eSSrinivas Kandagatla 664e2a5402eSSrinivas Kandagatla } 665e2a5402eSSrinivas Kandagatla 666e2a5402eSSrinivas Kandagatla return nvmem_find(dev_name); 667e2a5402eSSrinivas Kandagatla } 668e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_get); 669e2a5402eSSrinivas Kandagatla 670e2a5402eSSrinivas Kandagatla static int devm_nvmem_device_match(struct device *dev, void *res, void *data) 671e2a5402eSSrinivas Kandagatla { 672e2a5402eSSrinivas Kandagatla struct nvmem_device **nvmem = res; 673e2a5402eSSrinivas Kandagatla 674e2a5402eSSrinivas Kandagatla if (WARN_ON(!nvmem || !*nvmem)) 675e2a5402eSSrinivas Kandagatla return 0; 676e2a5402eSSrinivas Kandagatla 677e2a5402eSSrinivas Kandagatla return *nvmem == data; 678e2a5402eSSrinivas Kandagatla } 679e2a5402eSSrinivas Kandagatla 680e2a5402eSSrinivas Kandagatla static void devm_nvmem_device_release(struct device *dev, void *res) 681e2a5402eSSrinivas Kandagatla { 682e2a5402eSSrinivas Kandagatla nvmem_device_put(*(struct nvmem_device **)res); 683e2a5402eSSrinivas Kandagatla } 684e2a5402eSSrinivas Kandagatla 685e2a5402eSSrinivas Kandagatla /** 686e2a5402eSSrinivas Kandagatla * devm_nvmem_device_put() - put alredy got nvmem device 687e2a5402eSSrinivas Kandagatla * 68829143268SVivek Gautam * @dev: Device that uses the nvmem device. 689e2a5402eSSrinivas Kandagatla * @nvmem: pointer to nvmem device allocated by devm_nvmem_cell_get(), 690e2a5402eSSrinivas Kandagatla * that needs to be released. 691e2a5402eSSrinivas Kandagatla */ 692e2a5402eSSrinivas Kandagatla void devm_nvmem_device_put(struct device *dev, struct nvmem_device *nvmem) 693e2a5402eSSrinivas Kandagatla { 694e2a5402eSSrinivas Kandagatla int ret; 695e2a5402eSSrinivas Kandagatla 696e2a5402eSSrinivas Kandagatla ret = devres_release(dev, devm_nvmem_device_release, 697e2a5402eSSrinivas Kandagatla devm_nvmem_device_match, nvmem); 698e2a5402eSSrinivas Kandagatla 699e2a5402eSSrinivas Kandagatla WARN_ON(ret); 700e2a5402eSSrinivas Kandagatla } 701e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_device_put); 702e2a5402eSSrinivas Kandagatla 703e2a5402eSSrinivas Kandagatla /** 704e2a5402eSSrinivas Kandagatla * nvmem_device_put() - put alredy got nvmem device 705e2a5402eSSrinivas Kandagatla * 706e2a5402eSSrinivas Kandagatla * @nvmem: pointer to nvmem device that needs to be released. 707e2a5402eSSrinivas Kandagatla */ 708e2a5402eSSrinivas Kandagatla void nvmem_device_put(struct nvmem_device *nvmem) 709e2a5402eSSrinivas Kandagatla { 710e2a5402eSSrinivas Kandagatla __nvmem_device_put(nvmem); 711e2a5402eSSrinivas Kandagatla } 712e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_put); 713e2a5402eSSrinivas Kandagatla 714e2a5402eSSrinivas Kandagatla /** 715e2a5402eSSrinivas Kandagatla * devm_nvmem_device_get() - Get nvmem cell of device form a given id 716e2a5402eSSrinivas Kandagatla * 71729143268SVivek Gautam * @dev: Device that requests the nvmem device. 71829143268SVivek Gautam * @id: name id for the requested nvmem device. 719e2a5402eSSrinivas Kandagatla * 720e2a5402eSSrinivas Kandagatla * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_cell 721e2a5402eSSrinivas Kandagatla * on success. The nvmem_cell will be freed by the automatically once the 722e2a5402eSSrinivas Kandagatla * device is freed. 723e2a5402eSSrinivas Kandagatla */ 724e2a5402eSSrinivas Kandagatla struct nvmem_device *devm_nvmem_device_get(struct device *dev, const char *id) 725e2a5402eSSrinivas Kandagatla { 726e2a5402eSSrinivas Kandagatla struct nvmem_device **ptr, *nvmem; 727e2a5402eSSrinivas Kandagatla 728e2a5402eSSrinivas Kandagatla ptr = devres_alloc(devm_nvmem_device_release, sizeof(*ptr), GFP_KERNEL); 729e2a5402eSSrinivas Kandagatla if (!ptr) 730e2a5402eSSrinivas Kandagatla return ERR_PTR(-ENOMEM); 731e2a5402eSSrinivas Kandagatla 732e2a5402eSSrinivas Kandagatla nvmem = nvmem_device_get(dev, id); 733e2a5402eSSrinivas Kandagatla if (!IS_ERR(nvmem)) { 734e2a5402eSSrinivas Kandagatla *ptr = nvmem; 735e2a5402eSSrinivas Kandagatla devres_add(dev, ptr); 736e2a5402eSSrinivas Kandagatla } else { 737e2a5402eSSrinivas Kandagatla devres_free(ptr); 738e2a5402eSSrinivas Kandagatla } 739e2a5402eSSrinivas Kandagatla 740e2a5402eSSrinivas Kandagatla return nvmem; 741e2a5402eSSrinivas Kandagatla } 742e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_device_get); 743e2a5402eSSrinivas Kandagatla 74469aba794SSrinivas Kandagatla static struct nvmem_cell *nvmem_cell_get_from_list(const char *cell_id) 74569aba794SSrinivas Kandagatla { 74669aba794SSrinivas Kandagatla struct nvmem_cell *cell = NULL; 74769aba794SSrinivas Kandagatla struct nvmem_device *nvmem; 74869aba794SSrinivas Kandagatla 74969aba794SSrinivas Kandagatla nvmem = __nvmem_device_get(NULL, &cell, cell_id); 75069aba794SSrinivas Kandagatla if (IS_ERR(nvmem)) 75169aba794SSrinivas Kandagatla return ERR_CAST(nvmem); 75269aba794SSrinivas Kandagatla 75369aba794SSrinivas Kandagatla return cell; 75469aba794SSrinivas Kandagatla } 75569aba794SSrinivas Kandagatla 756*e701c67cSMasahiro Yamada #if IS_ENABLED(CONFIG_OF) 75769aba794SSrinivas Kandagatla /** 75869aba794SSrinivas Kandagatla * of_nvmem_cell_get() - Get a nvmem cell from given device node and cell id 75969aba794SSrinivas Kandagatla * 76029143268SVivek Gautam * @np: Device tree node that uses the nvmem cell. 761fd0c478cSVivek Gautam * @name: nvmem cell name from nvmem-cell-names property, or NULL 762fd0c478cSVivek Gautam * for the cell at index 0 (the lone cell with no accompanying 763fd0c478cSVivek Gautam * nvmem-cell-names property). 76469aba794SSrinivas Kandagatla * 76569aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 76669aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 76769aba794SSrinivas Kandagatla * nvmem_cell_put(). 76869aba794SSrinivas Kandagatla */ 76969aba794SSrinivas Kandagatla struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, 77069aba794SSrinivas Kandagatla const char *name) 77169aba794SSrinivas Kandagatla { 77269aba794SSrinivas Kandagatla struct device_node *cell_np, *nvmem_np; 77369aba794SSrinivas Kandagatla struct nvmem_cell *cell; 77469aba794SSrinivas Kandagatla struct nvmem_device *nvmem; 77569aba794SSrinivas Kandagatla const __be32 *addr; 776fd0c478cSVivek Gautam int rval, len; 777fd0c478cSVivek Gautam int index = 0; 77869aba794SSrinivas Kandagatla 779fd0c478cSVivek Gautam /* if cell name exists, find index to the name */ 780fd0c478cSVivek Gautam if (name) 78169aba794SSrinivas Kandagatla index = of_property_match_string(np, "nvmem-cell-names", name); 78269aba794SSrinivas Kandagatla 78369aba794SSrinivas Kandagatla cell_np = of_parse_phandle(np, "nvmem-cells", index); 78469aba794SSrinivas Kandagatla if (!cell_np) 78569aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 78669aba794SSrinivas Kandagatla 78769aba794SSrinivas Kandagatla nvmem_np = of_get_next_parent(cell_np); 78869aba794SSrinivas Kandagatla if (!nvmem_np) 78969aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 79069aba794SSrinivas Kandagatla 79169aba794SSrinivas Kandagatla nvmem = __nvmem_device_get(nvmem_np, NULL, NULL); 79269aba794SSrinivas Kandagatla if (IS_ERR(nvmem)) 79369aba794SSrinivas Kandagatla return ERR_CAST(nvmem); 79469aba794SSrinivas Kandagatla 79569aba794SSrinivas Kandagatla addr = of_get_property(cell_np, "reg", &len); 79669aba794SSrinivas Kandagatla if (!addr || (len < 2 * sizeof(u32))) { 7975f214ccdSRob Herring dev_err(&nvmem->dev, "nvmem: invalid reg on %pOF\n", 7985f214ccdSRob Herring cell_np); 79969aba794SSrinivas Kandagatla rval = -EINVAL; 80069aba794SSrinivas Kandagatla goto err_mem; 80169aba794SSrinivas Kandagatla } 80269aba794SSrinivas Kandagatla 80369aba794SSrinivas Kandagatla cell = kzalloc(sizeof(*cell), GFP_KERNEL); 80469aba794SSrinivas Kandagatla if (!cell) { 80569aba794SSrinivas Kandagatla rval = -ENOMEM; 80669aba794SSrinivas Kandagatla goto err_mem; 80769aba794SSrinivas Kandagatla } 80869aba794SSrinivas Kandagatla 80969aba794SSrinivas Kandagatla cell->nvmem = nvmem; 81069aba794SSrinivas Kandagatla cell->offset = be32_to_cpup(addr++); 81169aba794SSrinivas Kandagatla cell->bytes = be32_to_cpup(addr); 81269aba794SSrinivas Kandagatla cell->name = cell_np->name; 81369aba794SSrinivas Kandagatla 81469aba794SSrinivas Kandagatla addr = of_get_property(cell_np, "bits", &len); 81569aba794SSrinivas Kandagatla if (addr && len == (2 * sizeof(u32))) { 81669aba794SSrinivas Kandagatla cell->bit_offset = be32_to_cpup(addr++); 81769aba794SSrinivas Kandagatla cell->nbits = be32_to_cpup(addr); 81869aba794SSrinivas Kandagatla } 81969aba794SSrinivas Kandagatla 82069aba794SSrinivas Kandagatla if (cell->nbits) 82169aba794SSrinivas Kandagatla cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset, 82269aba794SSrinivas Kandagatla BITS_PER_BYTE); 82369aba794SSrinivas Kandagatla 82469aba794SSrinivas Kandagatla if (!IS_ALIGNED(cell->offset, nvmem->stride)) { 82569aba794SSrinivas Kandagatla dev_err(&nvmem->dev, 82669aba794SSrinivas Kandagatla "cell %s unaligned to nvmem stride %d\n", 82769aba794SSrinivas Kandagatla cell->name, nvmem->stride); 82869aba794SSrinivas Kandagatla rval = -EINVAL; 82969aba794SSrinivas Kandagatla goto err_sanity; 83069aba794SSrinivas Kandagatla } 83169aba794SSrinivas Kandagatla 83269aba794SSrinivas Kandagatla nvmem_cell_add(cell); 83369aba794SSrinivas Kandagatla 83469aba794SSrinivas Kandagatla return cell; 83569aba794SSrinivas Kandagatla 83669aba794SSrinivas Kandagatla err_sanity: 83769aba794SSrinivas Kandagatla kfree(cell); 83869aba794SSrinivas Kandagatla 83969aba794SSrinivas Kandagatla err_mem: 84069aba794SSrinivas Kandagatla __nvmem_device_put(nvmem); 84169aba794SSrinivas Kandagatla 84269aba794SSrinivas Kandagatla return ERR_PTR(rval); 84369aba794SSrinivas Kandagatla } 84469aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(of_nvmem_cell_get); 84569aba794SSrinivas Kandagatla #endif 84669aba794SSrinivas Kandagatla 84769aba794SSrinivas Kandagatla /** 84869aba794SSrinivas Kandagatla * nvmem_cell_get() - Get nvmem cell of device form a given cell name 84969aba794SSrinivas Kandagatla * 85029143268SVivek Gautam * @dev: Device that requests the nvmem cell. 85129143268SVivek Gautam * @cell_id: nvmem cell name to get. 85269aba794SSrinivas Kandagatla * 85369aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 85469aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 85569aba794SSrinivas Kandagatla * nvmem_cell_put(). 85669aba794SSrinivas Kandagatla */ 85769aba794SSrinivas Kandagatla struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *cell_id) 85869aba794SSrinivas Kandagatla { 85969aba794SSrinivas Kandagatla struct nvmem_cell *cell; 86069aba794SSrinivas Kandagatla 86169aba794SSrinivas Kandagatla if (dev->of_node) { /* try dt first */ 86269aba794SSrinivas Kandagatla cell = of_nvmem_cell_get(dev->of_node, cell_id); 86369aba794SSrinivas Kandagatla if (!IS_ERR(cell) || PTR_ERR(cell) == -EPROBE_DEFER) 86469aba794SSrinivas Kandagatla return cell; 86569aba794SSrinivas Kandagatla } 86669aba794SSrinivas Kandagatla 86769aba794SSrinivas Kandagatla return nvmem_cell_get_from_list(cell_id); 86869aba794SSrinivas Kandagatla } 86969aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_get); 87069aba794SSrinivas Kandagatla 87169aba794SSrinivas Kandagatla static void devm_nvmem_cell_release(struct device *dev, void *res) 87269aba794SSrinivas Kandagatla { 87369aba794SSrinivas Kandagatla nvmem_cell_put(*(struct nvmem_cell **)res); 87469aba794SSrinivas Kandagatla } 87569aba794SSrinivas Kandagatla 87669aba794SSrinivas Kandagatla /** 87769aba794SSrinivas Kandagatla * devm_nvmem_cell_get() - Get nvmem cell of device form a given id 87869aba794SSrinivas Kandagatla * 87929143268SVivek Gautam * @dev: Device that requests the nvmem cell. 88029143268SVivek Gautam * @id: nvmem cell name id to get. 88169aba794SSrinivas Kandagatla * 88269aba794SSrinivas Kandagatla * Return: Will be an ERR_PTR() on error or a valid pointer 88369aba794SSrinivas Kandagatla * to a struct nvmem_cell. The nvmem_cell will be freed by the 88469aba794SSrinivas Kandagatla * automatically once the device is freed. 88569aba794SSrinivas Kandagatla */ 88669aba794SSrinivas Kandagatla struct nvmem_cell *devm_nvmem_cell_get(struct device *dev, const char *id) 88769aba794SSrinivas Kandagatla { 88869aba794SSrinivas Kandagatla struct nvmem_cell **ptr, *cell; 88969aba794SSrinivas Kandagatla 89069aba794SSrinivas Kandagatla ptr = devres_alloc(devm_nvmem_cell_release, sizeof(*ptr), GFP_KERNEL); 89169aba794SSrinivas Kandagatla if (!ptr) 89269aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 89369aba794SSrinivas Kandagatla 89469aba794SSrinivas Kandagatla cell = nvmem_cell_get(dev, id); 89569aba794SSrinivas Kandagatla if (!IS_ERR(cell)) { 89669aba794SSrinivas Kandagatla *ptr = cell; 89769aba794SSrinivas Kandagatla devres_add(dev, ptr); 89869aba794SSrinivas Kandagatla } else { 89969aba794SSrinivas Kandagatla devres_free(ptr); 90069aba794SSrinivas Kandagatla } 90169aba794SSrinivas Kandagatla 90269aba794SSrinivas Kandagatla return cell; 90369aba794SSrinivas Kandagatla } 90469aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(devm_nvmem_cell_get); 90569aba794SSrinivas Kandagatla 90669aba794SSrinivas Kandagatla static int devm_nvmem_cell_match(struct device *dev, void *res, void *data) 90769aba794SSrinivas Kandagatla { 90869aba794SSrinivas Kandagatla struct nvmem_cell **c = res; 90969aba794SSrinivas Kandagatla 91069aba794SSrinivas Kandagatla if (WARN_ON(!c || !*c)) 91169aba794SSrinivas Kandagatla return 0; 91269aba794SSrinivas Kandagatla 91369aba794SSrinivas Kandagatla return *c == data; 91469aba794SSrinivas Kandagatla } 91569aba794SSrinivas Kandagatla 91669aba794SSrinivas Kandagatla /** 91769aba794SSrinivas Kandagatla * devm_nvmem_cell_put() - Release previously allocated nvmem cell 91869aba794SSrinivas Kandagatla * from devm_nvmem_cell_get. 91969aba794SSrinivas Kandagatla * 92029143268SVivek Gautam * @dev: Device that requests the nvmem cell. 92129143268SVivek Gautam * @cell: Previously allocated nvmem cell by devm_nvmem_cell_get(). 92269aba794SSrinivas Kandagatla */ 92369aba794SSrinivas Kandagatla void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell) 92469aba794SSrinivas Kandagatla { 92569aba794SSrinivas Kandagatla int ret; 92669aba794SSrinivas Kandagatla 92769aba794SSrinivas Kandagatla ret = devres_release(dev, devm_nvmem_cell_release, 92869aba794SSrinivas Kandagatla devm_nvmem_cell_match, cell); 92969aba794SSrinivas Kandagatla 93069aba794SSrinivas Kandagatla WARN_ON(ret); 93169aba794SSrinivas Kandagatla } 93269aba794SSrinivas Kandagatla EXPORT_SYMBOL(devm_nvmem_cell_put); 93369aba794SSrinivas Kandagatla 93469aba794SSrinivas Kandagatla /** 93569aba794SSrinivas Kandagatla * nvmem_cell_put() - Release previously allocated nvmem cell. 93669aba794SSrinivas Kandagatla * 93729143268SVivek Gautam * @cell: Previously allocated nvmem cell by nvmem_cell_get(). 93869aba794SSrinivas Kandagatla */ 93969aba794SSrinivas Kandagatla void nvmem_cell_put(struct nvmem_cell *cell) 94069aba794SSrinivas Kandagatla { 94169aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 94269aba794SSrinivas Kandagatla 94369aba794SSrinivas Kandagatla __nvmem_device_put(nvmem); 94469aba794SSrinivas Kandagatla nvmem_cell_drop(cell); 94569aba794SSrinivas Kandagatla } 94669aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_put); 94769aba794SSrinivas Kandagatla 948f7c04f16SMasahiro Yamada static void nvmem_shift_read_buffer_in_place(struct nvmem_cell *cell, void *buf) 94969aba794SSrinivas Kandagatla { 95069aba794SSrinivas Kandagatla u8 *p, *b; 95169aba794SSrinivas Kandagatla int i, bit_offset = cell->bit_offset; 95269aba794SSrinivas Kandagatla 95369aba794SSrinivas Kandagatla p = b = buf; 95469aba794SSrinivas Kandagatla if (bit_offset) { 95569aba794SSrinivas Kandagatla /* First shift */ 95669aba794SSrinivas Kandagatla *b++ >>= bit_offset; 95769aba794SSrinivas Kandagatla 95869aba794SSrinivas Kandagatla /* setup rest of the bytes if any */ 95969aba794SSrinivas Kandagatla for (i = 1; i < cell->bytes; i++) { 96069aba794SSrinivas Kandagatla /* Get bits from next byte and shift them towards msb */ 96169aba794SSrinivas Kandagatla *p |= *b << (BITS_PER_BYTE - bit_offset); 96269aba794SSrinivas Kandagatla 96369aba794SSrinivas Kandagatla p = b; 96469aba794SSrinivas Kandagatla *b++ >>= bit_offset; 96569aba794SSrinivas Kandagatla } 96669aba794SSrinivas Kandagatla 96769aba794SSrinivas Kandagatla /* result fits in less bytes */ 96869aba794SSrinivas Kandagatla if (cell->bytes != DIV_ROUND_UP(cell->nbits, BITS_PER_BYTE)) 96969aba794SSrinivas Kandagatla *p-- = 0; 97069aba794SSrinivas Kandagatla } 97169aba794SSrinivas Kandagatla /* clear msb bits if any leftover in the last byte */ 97269aba794SSrinivas Kandagatla *p &= GENMASK((cell->nbits%BITS_PER_BYTE) - 1, 0); 97369aba794SSrinivas Kandagatla } 97469aba794SSrinivas Kandagatla 97569aba794SSrinivas Kandagatla static int __nvmem_cell_read(struct nvmem_device *nvmem, 97669aba794SSrinivas Kandagatla struct nvmem_cell *cell, 97769aba794SSrinivas Kandagatla void *buf, size_t *len) 97869aba794SSrinivas Kandagatla { 97969aba794SSrinivas Kandagatla int rc; 98069aba794SSrinivas Kandagatla 981795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, cell->offset, buf, cell->bytes); 98269aba794SSrinivas Kandagatla 983287980e4SArnd Bergmann if (rc) 98469aba794SSrinivas Kandagatla return rc; 98569aba794SSrinivas Kandagatla 98669aba794SSrinivas Kandagatla /* shift bits in-place */ 987cbf854abSAxel Lin if (cell->bit_offset || cell->nbits) 98869aba794SSrinivas Kandagatla nvmem_shift_read_buffer_in_place(cell, buf); 98969aba794SSrinivas Kandagatla 9903b4a6877SVivek Gautam if (len) 99169aba794SSrinivas Kandagatla *len = cell->bytes; 99269aba794SSrinivas Kandagatla 99369aba794SSrinivas Kandagatla return 0; 99469aba794SSrinivas Kandagatla } 99569aba794SSrinivas Kandagatla 99669aba794SSrinivas Kandagatla /** 99769aba794SSrinivas Kandagatla * nvmem_cell_read() - Read a given nvmem cell 99869aba794SSrinivas Kandagatla * 99969aba794SSrinivas Kandagatla * @cell: nvmem cell to be read. 10003b4a6877SVivek Gautam * @len: pointer to length of cell which will be populated on successful read; 10013b4a6877SVivek Gautam * can be NULL. 100269aba794SSrinivas Kandagatla * 1003b577fafcSBrian Norris * Return: ERR_PTR() on error or a valid pointer to a buffer on success. The 1004b577fafcSBrian Norris * buffer should be freed by the consumer with a kfree(). 100569aba794SSrinivas Kandagatla */ 100669aba794SSrinivas Kandagatla void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len) 100769aba794SSrinivas Kandagatla { 100869aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 100969aba794SSrinivas Kandagatla u8 *buf; 101069aba794SSrinivas Kandagatla int rc; 101169aba794SSrinivas Kandagatla 1012795ddd18SSrinivas Kandagatla if (!nvmem) 101369aba794SSrinivas Kandagatla return ERR_PTR(-EINVAL); 101469aba794SSrinivas Kandagatla 101569aba794SSrinivas Kandagatla buf = kzalloc(cell->bytes, GFP_KERNEL); 101669aba794SSrinivas Kandagatla if (!buf) 101769aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 101869aba794SSrinivas Kandagatla 101969aba794SSrinivas Kandagatla rc = __nvmem_cell_read(nvmem, cell, buf, len); 1020287980e4SArnd Bergmann if (rc) { 102169aba794SSrinivas Kandagatla kfree(buf); 102269aba794SSrinivas Kandagatla return ERR_PTR(rc); 102369aba794SSrinivas Kandagatla } 102469aba794SSrinivas Kandagatla 102569aba794SSrinivas Kandagatla return buf; 102669aba794SSrinivas Kandagatla } 102769aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_read); 102869aba794SSrinivas Kandagatla 1029f7c04f16SMasahiro Yamada static void *nvmem_cell_prepare_write_buffer(struct nvmem_cell *cell, 103069aba794SSrinivas Kandagatla u8 *_buf, int len) 103169aba794SSrinivas Kandagatla { 103269aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 103369aba794SSrinivas Kandagatla int i, rc, nbits, bit_offset = cell->bit_offset; 103469aba794SSrinivas Kandagatla u8 v, *p, *buf, *b, pbyte, pbits; 103569aba794SSrinivas Kandagatla 103669aba794SSrinivas Kandagatla nbits = cell->nbits; 103769aba794SSrinivas Kandagatla buf = kzalloc(cell->bytes, GFP_KERNEL); 103869aba794SSrinivas Kandagatla if (!buf) 103969aba794SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 104069aba794SSrinivas Kandagatla 104169aba794SSrinivas Kandagatla memcpy(buf, _buf, len); 104269aba794SSrinivas Kandagatla p = b = buf; 104369aba794SSrinivas Kandagatla 104469aba794SSrinivas Kandagatla if (bit_offset) { 104569aba794SSrinivas Kandagatla pbyte = *b; 104669aba794SSrinivas Kandagatla *b <<= bit_offset; 104769aba794SSrinivas Kandagatla 104869aba794SSrinivas Kandagatla /* setup the first byte with lsb bits from nvmem */ 1049795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, cell->offset, &v, 1); 105069aba794SSrinivas Kandagatla *b++ |= GENMASK(bit_offset - 1, 0) & v; 105169aba794SSrinivas Kandagatla 105269aba794SSrinivas Kandagatla /* setup rest of the byte if any */ 105369aba794SSrinivas Kandagatla for (i = 1; i < cell->bytes; i++) { 105469aba794SSrinivas Kandagatla /* Get last byte bits and shift them towards lsb */ 105569aba794SSrinivas Kandagatla pbits = pbyte >> (BITS_PER_BYTE - 1 - bit_offset); 105669aba794SSrinivas Kandagatla pbyte = *b; 105769aba794SSrinivas Kandagatla p = b; 105869aba794SSrinivas Kandagatla *b <<= bit_offset; 105969aba794SSrinivas Kandagatla *b++ |= pbits; 106069aba794SSrinivas Kandagatla } 106169aba794SSrinivas Kandagatla } 106269aba794SSrinivas Kandagatla 106369aba794SSrinivas Kandagatla /* if it's not end on byte boundary */ 106469aba794SSrinivas Kandagatla if ((nbits + bit_offset) % BITS_PER_BYTE) { 106569aba794SSrinivas Kandagatla /* setup the last byte with msb bits from nvmem */ 1066795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, 106769aba794SSrinivas Kandagatla cell->offset + cell->bytes - 1, &v, 1); 106869aba794SSrinivas Kandagatla *p |= GENMASK(7, (nbits + bit_offset) % BITS_PER_BYTE) & v; 106969aba794SSrinivas Kandagatla 107069aba794SSrinivas Kandagatla } 107169aba794SSrinivas Kandagatla 107269aba794SSrinivas Kandagatla return buf; 107369aba794SSrinivas Kandagatla } 107469aba794SSrinivas Kandagatla 107569aba794SSrinivas Kandagatla /** 107669aba794SSrinivas Kandagatla * nvmem_cell_write() - Write to a given nvmem cell 107769aba794SSrinivas Kandagatla * 107869aba794SSrinivas Kandagatla * @cell: nvmem cell to be written. 107969aba794SSrinivas Kandagatla * @buf: Buffer to be written. 108069aba794SSrinivas Kandagatla * @len: length of buffer to be written to nvmem cell. 108169aba794SSrinivas Kandagatla * 108269aba794SSrinivas Kandagatla * Return: length of bytes written or negative on failure. 108369aba794SSrinivas Kandagatla */ 108469aba794SSrinivas Kandagatla int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len) 108569aba794SSrinivas Kandagatla { 108669aba794SSrinivas Kandagatla struct nvmem_device *nvmem = cell->nvmem; 108769aba794SSrinivas Kandagatla int rc; 108869aba794SSrinivas Kandagatla 1089795ddd18SSrinivas Kandagatla if (!nvmem || nvmem->read_only || 109069aba794SSrinivas Kandagatla (cell->bit_offset == 0 && len != cell->bytes)) 109169aba794SSrinivas Kandagatla return -EINVAL; 109269aba794SSrinivas Kandagatla 109369aba794SSrinivas Kandagatla if (cell->bit_offset || cell->nbits) { 109469aba794SSrinivas Kandagatla buf = nvmem_cell_prepare_write_buffer(cell, buf, len); 109569aba794SSrinivas Kandagatla if (IS_ERR(buf)) 109669aba794SSrinivas Kandagatla return PTR_ERR(buf); 109769aba794SSrinivas Kandagatla } 109869aba794SSrinivas Kandagatla 1099795ddd18SSrinivas Kandagatla rc = nvmem_reg_write(nvmem, cell->offset, buf, cell->bytes); 110069aba794SSrinivas Kandagatla 110169aba794SSrinivas Kandagatla /* free the tmp buffer */ 1102ace22170SAxel Lin if (cell->bit_offset || cell->nbits) 110369aba794SSrinivas Kandagatla kfree(buf); 110469aba794SSrinivas Kandagatla 1105287980e4SArnd Bergmann if (rc) 110669aba794SSrinivas Kandagatla return rc; 110769aba794SSrinivas Kandagatla 110869aba794SSrinivas Kandagatla return len; 110969aba794SSrinivas Kandagatla } 111069aba794SSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_cell_write); 111169aba794SSrinivas Kandagatla 1112e2a5402eSSrinivas Kandagatla /** 1113d026d70aSLeonard Crestez * nvmem_cell_read_u32() - Read a cell value as an u32 1114d026d70aSLeonard Crestez * 1115d026d70aSLeonard Crestez * @dev: Device that requests the nvmem cell. 1116d026d70aSLeonard Crestez * @cell_id: Name of nvmem cell to read. 1117d026d70aSLeonard Crestez * @val: pointer to output value. 1118d026d70aSLeonard Crestez * 1119d026d70aSLeonard Crestez * Return: 0 on success or negative errno. 1120d026d70aSLeonard Crestez */ 1121d026d70aSLeonard Crestez int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val) 1122d026d70aSLeonard Crestez { 1123d026d70aSLeonard Crestez struct nvmem_cell *cell; 1124d026d70aSLeonard Crestez void *buf; 1125d026d70aSLeonard Crestez size_t len; 1126d026d70aSLeonard Crestez 1127d026d70aSLeonard Crestez cell = nvmem_cell_get(dev, cell_id); 1128d026d70aSLeonard Crestez if (IS_ERR(cell)) 1129d026d70aSLeonard Crestez return PTR_ERR(cell); 1130d026d70aSLeonard Crestez 1131d026d70aSLeonard Crestez buf = nvmem_cell_read(cell, &len); 1132d026d70aSLeonard Crestez if (IS_ERR(buf)) { 1133d026d70aSLeonard Crestez nvmem_cell_put(cell); 1134d026d70aSLeonard Crestez return PTR_ERR(buf); 1135d026d70aSLeonard Crestez } 1136d026d70aSLeonard Crestez if (len != sizeof(*val)) { 1137d026d70aSLeonard Crestez kfree(buf); 1138d026d70aSLeonard Crestez nvmem_cell_put(cell); 1139d026d70aSLeonard Crestez return -EINVAL; 1140d026d70aSLeonard Crestez } 1141d026d70aSLeonard Crestez memcpy(val, buf, sizeof(*val)); 1142d026d70aSLeonard Crestez 1143d026d70aSLeonard Crestez kfree(buf); 1144d026d70aSLeonard Crestez nvmem_cell_put(cell); 1145d026d70aSLeonard Crestez return 0; 1146d026d70aSLeonard Crestez } 1147d026d70aSLeonard Crestez EXPORT_SYMBOL_GPL(nvmem_cell_read_u32); 1148d026d70aSLeonard Crestez 1149d026d70aSLeonard Crestez /** 1150e2a5402eSSrinivas Kandagatla * nvmem_device_cell_read() - Read a given nvmem device and cell 1151e2a5402eSSrinivas Kandagatla * 1152e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to read from. 1153e2a5402eSSrinivas Kandagatla * @info: nvmem cell info to be read. 1154e2a5402eSSrinivas Kandagatla * @buf: buffer pointer which will be populated on successful read. 1155e2a5402eSSrinivas Kandagatla * 1156e2a5402eSSrinivas Kandagatla * Return: length of successful bytes read on success and negative 1157e2a5402eSSrinivas Kandagatla * error code on error. 1158e2a5402eSSrinivas Kandagatla */ 1159e2a5402eSSrinivas Kandagatla ssize_t nvmem_device_cell_read(struct nvmem_device *nvmem, 1160e2a5402eSSrinivas Kandagatla struct nvmem_cell_info *info, void *buf) 1161e2a5402eSSrinivas Kandagatla { 1162e2a5402eSSrinivas Kandagatla struct nvmem_cell cell; 1163e2a5402eSSrinivas Kandagatla int rc; 1164e2a5402eSSrinivas Kandagatla ssize_t len; 1165e2a5402eSSrinivas Kandagatla 1166795ddd18SSrinivas Kandagatla if (!nvmem) 1167e2a5402eSSrinivas Kandagatla return -EINVAL; 1168e2a5402eSSrinivas Kandagatla 1169e2a5402eSSrinivas Kandagatla rc = nvmem_cell_info_to_nvmem_cell(nvmem, info, &cell); 1170287980e4SArnd Bergmann if (rc) 1171e2a5402eSSrinivas Kandagatla return rc; 1172e2a5402eSSrinivas Kandagatla 1173e2a5402eSSrinivas Kandagatla rc = __nvmem_cell_read(nvmem, &cell, buf, &len); 1174287980e4SArnd Bergmann if (rc) 1175e2a5402eSSrinivas Kandagatla return rc; 1176e2a5402eSSrinivas Kandagatla 1177e2a5402eSSrinivas Kandagatla return len; 1178e2a5402eSSrinivas Kandagatla } 1179e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_cell_read); 1180e2a5402eSSrinivas Kandagatla 1181e2a5402eSSrinivas Kandagatla /** 1182e2a5402eSSrinivas Kandagatla * nvmem_device_cell_write() - Write cell to a given nvmem device 1183e2a5402eSSrinivas Kandagatla * 1184e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to be written to. 118529143268SVivek Gautam * @info: nvmem cell info to be written. 1186e2a5402eSSrinivas Kandagatla * @buf: buffer to be written to cell. 1187e2a5402eSSrinivas Kandagatla * 1188e2a5402eSSrinivas Kandagatla * Return: length of bytes written or negative error code on failure. 1189e2a5402eSSrinivas Kandagatla * */ 1190e2a5402eSSrinivas Kandagatla int nvmem_device_cell_write(struct nvmem_device *nvmem, 1191e2a5402eSSrinivas Kandagatla struct nvmem_cell_info *info, void *buf) 1192e2a5402eSSrinivas Kandagatla { 1193e2a5402eSSrinivas Kandagatla struct nvmem_cell cell; 1194e2a5402eSSrinivas Kandagatla int rc; 1195e2a5402eSSrinivas Kandagatla 1196795ddd18SSrinivas Kandagatla if (!nvmem) 1197e2a5402eSSrinivas Kandagatla return -EINVAL; 1198e2a5402eSSrinivas Kandagatla 1199e2a5402eSSrinivas Kandagatla rc = nvmem_cell_info_to_nvmem_cell(nvmem, info, &cell); 1200287980e4SArnd Bergmann if (rc) 1201e2a5402eSSrinivas Kandagatla return rc; 1202e2a5402eSSrinivas Kandagatla 1203e2a5402eSSrinivas Kandagatla return nvmem_cell_write(&cell, buf, cell.bytes); 1204e2a5402eSSrinivas Kandagatla } 1205e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_cell_write); 1206e2a5402eSSrinivas Kandagatla 1207e2a5402eSSrinivas Kandagatla /** 1208e2a5402eSSrinivas Kandagatla * nvmem_device_read() - Read from a given nvmem device 1209e2a5402eSSrinivas Kandagatla * 1210e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to read from. 1211e2a5402eSSrinivas Kandagatla * @offset: offset in nvmem device. 1212e2a5402eSSrinivas Kandagatla * @bytes: number of bytes to read. 1213e2a5402eSSrinivas Kandagatla * @buf: buffer pointer which will be populated on successful read. 1214e2a5402eSSrinivas Kandagatla * 1215e2a5402eSSrinivas Kandagatla * Return: length of successful bytes read on success and negative 1216e2a5402eSSrinivas Kandagatla * error code on error. 1217e2a5402eSSrinivas Kandagatla */ 1218e2a5402eSSrinivas Kandagatla int nvmem_device_read(struct nvmem_device *nvmem, 1219e2a5402eSSrinivas Kandagatla unsigned int offset, 1220e2a5402eSSrinivas Kandagatla size_t bytes, void *buf) 1221e2a5402eSSrinivas Kandagatla { 1222e2a5402eSSrinivas Kandagatla int rc; 1223e2a5402eSSrinivas Kandagatla 1224795ddd18SSrinivas Kandagatla if (!nvmem) 1225e2a5402eSSrinivas Kandagatla return -EINVAL; 1226e2a5402eSSrinivas Kandagatla 1227795ddd18SSrinivas Kandagatla rc = nvmem_reg_read(nvmem, offset, buf, bytes); 1228e2a5402eSSrinivas Kandagatla 1229287980e4SArnd Bergmann if (rc) 1230e2a5402eSSrinivas Kandagatla return rc; 1231e2a5402eSSrinivas Kandagatla 1232e2a5402eSSrinivas Kandagatla return bytes; 1233e2a5402eSSrinivas Kandagatla } 1234e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_read); 1235e2a5402eSSrinivas Kandagatla 1236e2a5402eSSrinivas Kandagatla /** 1237e2a5402eSSrinivas Kandagatla * nvmem_device_write() - Write cell to a given nvmem device 1238e2a5402eSSrinivas Kandagatla * 1239e2a5402eSSrinivas Kandagatla * @nvmem: nvmem device to be written to. 1240e2a5402eSSrinivas Kandagatla * @offset: offset in nvmem device. 1241e2a5402eSSrinivas Kandagatla * @bytes: number of bytes to write. 1242e2a5402eSSrinivas Kandagatla * @buf: buffer to be written. 1243e2a5402eSSrinivas Kandagatla * 1244e2a5402eSSrinivas Kandagatla * Return: length of bytes written or negative error code on failure. 1245e2a5402eSSrinivas Kandagatla * */ 1246e2a5402eSSrinivas Kandagatla int nvmem_device_write(struct nvmem_device *nvmem, 1247e2a5402eSSrinivas Kandagatla unsigned int offset, 1248e2a5402eSSrinivas Kandagatla size_t bytes, void *buf) 1249e2a5402eSSrinivas Kandagatla { 1250e2a5402eSSrinivas Kandagatla int rc; 1251e2a5402eSSrinivas Kandagatla 1252795ddd18SSrinivas Kandagatla if (!nvmem) 1253e2a5402eSSrinivas Kandagatla return -EINVAL; 1254e2a5402eSSrinivas Kandagatla 1255795ddd18SSrinivas Kandagatla rc = nvmem_reg_write(nvmem, offset, buf, bytes); 1256e2a5402eSSrinivas Kandagatla 1257287980e4SArnd Bergmann if (rc) 1258e2a5402eSSrinivas Kandagatla return rc; 1259e2a5402eSSrinivas Kandagatla 1260e2a5402eSSrinivas Kandagatla 1261e2a5402eSSrinivas Kandagatla return bytes; 1262e2a5402eSSrinivas Kandagatla } 1263e2a5402eSSrinivas Kandagatla EXPORT_SYMBOL_GPL(nvmem_device_write); 1264e2a5402eSSrinivas Kandagatla 1265eace75cfSSrinivas Kandagatla static int __init nvmem_init(void) 1266eace75cfSSrinivas Kandagatla { 1267eace75cfSSrinivas Kandagatla return bus_register(&nvmem_bus_type); 1268eace75cfSSrinivas Kandagatla } 1269eace75cfSSrinivas Kandagatla 1270eace75cfSSrinivas Kandagatla static void __exit nvmem_exit(void) 1271eace75cfSSrinivas Kandagatla { 1272eace75cfSSrinivas Kandagatla bus_unregister(&nvmem_bus_type); 1273eace75cfSSrinivas Kandagatla } 1274eace75cfSSrinivas Kandagatla 1275eace75cfSSrinivas Kandagatla subsys_initcall(nvmem_init); 1276eace75cfSSrinivas Kandagatla module_exit(nvmem_exit); 1277eace75cfSSrinivas Kandagatla 1278eace75cfSSrinivas Kandagatla MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org"); 1279eace75cfSSrinivas Kandagatla MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com"); 1280eace75cfSSrinivas Kandagatla MODULE_DESCRIPTION("nvmem Driver Core"); 1281eace75cfSSrinivas Kandagatla MODULE_LICENSE("GPL v2"); 1282