diff options
Diffstat (limited to 'drivers/nvmem/core.c')
-rw-r--r-- | drivers/nvmem/core.c | 127 |
1 files changed, 94 insertions, 33 deletions
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index fed387c43a..bf393fc180 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -15,8 +15,7 @@ struct nvmem_device { const char *name; - struct device_d dev; - const struct nvmem_bus *bus; + struct device dev; struct list_head node; int stride; int word_size; @@ -26,10 +25,16 @@ struct nvmem_device { bool read_only; struct cdev cdev; void *priv; + nvmem_cell_post_process_t cell_post_process; + int (*reg_write)(void *ctx, unsigned int reg, + const void *val, size_t val_size); + int (*reg_read)(void *ctx, unsigned int reg, + void *val, size_t val_size); }; struct nvmem_cell { const char *name; + const char *id; int offset; int bytes; int bit_offset; @@ -95,12 +100,12 @@ static struct cdev_operations nvmem_chrdev_ops = { static int nvmem_register_cdev(struct nvmem_device *nvmem, const char *name) { - struct device_d *dev = &nvmem->dev; + struct device *dev = &nvmem->dev; struct cdev *cdev = &nvmem->cdev; const char *alias; int ret; - alias = of_alias_get(dev->device_node); + alias = of_alias_get(dev->of_node); cdev->name = xstrdup(alias ?: name); cdev->ops = &nvmem_chrdev_ops; @@ -111,7 +116,7 @@ static int nvmem_register_cdev(struct nvmem_device *nvmem, const char *name) if (ret) return ret; - of_parse_partitions(cdev, dev->device_node); + of_parse_partitions(cdev, dev->of_node); of_partitions_register_fixup(cdev); return 0; @@ -125,7 +130,7 @@ static struct nvmem_device *of_nvmem_find(struct device_node *nvmem_np) return NULL; list_for_each_entry(dev, &nvmem_devs, node) - if (dev->dev.device_node == nvmem_np) + if (dev->dev.of_node == nvmem_np) return dev; return NULL; @@ -136,7 +141,7 @@ static struct nvmem_cell *nvmem_find_cell(const char *cell_id) struct nvmem_cell *p; list_for_each_entry(p, &nvmem_cells, node) - if (p && !strcmp(p->name, cell_id)) + if (!strcmp(p->name, cell_id)) return p; return NULL; @@ -145,6 +150,7 @@ static struct nvmem_cell *nvmem_find_cell(const char *cell_id) static void nvmem_cell_drop(struct nvmem_cell *cell) { list_del(&cell->node); + kfree(cell->id); kfree(cell); } @@ -205,12 +211,14 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) nvmem->word_size = config->word_size; nvmem->size = config->size; nvmem->dev.parent = config->dev; - nvmem->bus = config->bus; - np = config->cdev ? config->cdev->device_node : config->dev->device_node; - nvmem->dev.device_node = np; + nvmem->reg_read = config->reg_read; + nvmem->reg_write = config->reg_write; + np = config->cdev ? cdev_of_node(config->cdev) : config->dev->of_node; + nvmem->dev.of_node = np; nvmem->priv = config->priv; + nvmem->cell_post_process = config->cell_post_process; - if (config->read_only || !config->bus->write || of_property_read_bool(np, "read-only")) + if (config->read_only || !config->reg_write || of_property_read_bool(np, "read-only")) nvmem->read_only = true; dev_set_name(&nvmem->dev, config->name); @@ -325,12 +333,13 @@ EXPORT_SYMBOL_GPL(of_nvmem_device_get); * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device * on success. */ -struct nvmem_device *nvmem_device_get(struct device_d *dev, const char *dev_name) +struct nvmem_device *nvmem_device_get(struct device *dev, + const char *dev_name) { - if (dev->device_node) { /* try dt first */ + if (dev->of_node) { /* try dt first */ struct nvmem_device *nvmem; - nvmem = of_nvmem_device_get(dev->device_node, dev_name); + nvmem = of_nvmem_device_get(dev->of_node, dev_name); if (!IS_ERR(nvmem) || PTR_ERR(nvmem) == -EPROBE_DEFER) return nvmem; @@ -400,8 +409,7 @@ struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, addr = of_get_property(cell_np, "reg", &len); if (!addr || (len < 2 * sizeof(u32))) { - dev_err(&nvmem->dev, "nvmem: invalid reg on %s\n", - cell_np->full_name); + dev_err(&nvmem->dev, "nvmem: invalid reg on %pOF\n", cell_np); rval = -EINVAL; goto err_mem; } @@ -416,6 +424,7 @@ struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, cell->offset = be32_to_cpup(addr++); cell->bytes = be32_to_cpup(addr); cell->name = cell_np->name; + cell->id = kstrdup_const(name, GFP_KERNEL); addr = of_get_property(cell_np, "bits", &len); if (addr && len == (2 * sizeof(u32))) { @@ -463,12 +472,12 @@ EXPORT_SYMBOL_GPL(of_nvmem_cell_get); * to a struct nvmem_cell. The nvmem_cell will be freed by the * nvmem_cell_put(). */ -struct nvmem_cell *nvmem_cell_get(struct device_d *dev, const char *cell_id) +struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *cell_id) { struct nvmem_cell *cell; - if (dev->device_node) { /* try dt first */ - cell = of_nvmem_cell_get(dev->device_node, cell_id); + if (dev->of_node) { /* try dt first */ + cell = of_nvmem_cell_get(dev->of_node, cell_id); if (!IS_ERR(cell) || PTR_ERR(cell) == -EPROBE_DEFER) return cell; } @@ -525,14 +534,21 @@ static int __nvmem_cell_read(struct nvmem_device *nvmem, { int rc; - rc = nvmem->bus->read(nvmem->priv, cell->offset, buf, cell->bytes); - if (IS_ERR_VALUE(rc)) + rc = nvmem->reg_read(nvmem->priv, cell->offset, buf, cell->bytes); + if (rc < 0) return rc; /* shift bits in-place */ if (cell->bit_offset || cell->nbits) nvmem_shift_read_buffer_in_place(cell, buf); + if (nvmem->cell_post_process) { + rc = nvmem->cell_post_process(nvmem->priv, cell->id, + cell->offset, buf, cell->bytes); + if (rc) + return rc; + } + *len = cell->bytes; return 0; @@ -561,7 +577,7 @@ void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len) return ERR_PTR(-ENOMEM); rc = __nvmem_cell_read(nvmem, cell, buf, len); - if (IS_ERR_VALUE(rc)) { + if (rc < 0) { kfree(buf); return ERR_PTR(rc); } @@ -590,7 +606,10 @@ static inline void *nvmem_cell_prepare_write_buffer(struct nvmem_cell *cell, *b <<= bit_offset; /* setup the first byte with lsb bits from nvmem */ - rc = nvmem->bus->read(nvmem->priv, cell->offset, &v, 1); + rc = nvmem->reg_read(nvmem->priv, cell->offset, &v, 1); + if (rc < 0) + return ERR_PTR(rc); + *b++ |= GENMASK(bit_offset - 1, 0) & v; /* setup rest of the byte if any */ @@ -607,8 +626,11 @@ static inline void *nvmem_cell_prepare_write_buffer(struct nvmem_cell *cell, /* if it's not end on byte boundary */ if ((nbits + bit_offset) % BITS_PER_BYTE) { /* setup the last byte with msb bits from nvmem */ - rc = nvmem->bus->read(nvmem->priv, cell->offset + cell->bytes - 1, + rc = nvmem->reg_read(nvmem->priv, cell->offset + cell->bytes - 1, &v, 1); + if (rc < 0) + return ERR_PTR(rc); + *p |= GENMASK(7, (nbits + bit_offset) % BITS_PER_BYTE) & v; } @@ -640,13 +662,13 @@ int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len) return PTR_ERR(buf); } - rc = nvmem->bus->write(nvmem->priv, cell->offset, buf, cell->bytes); + rc = nvmem->reg_write(nvmem->priv, cell->offset, buf, cell->bytes); /* free the tmp buffer */ if (cell->bit_offset || cell->nbits) kfree(buf); - if (IS_ERR_VALUE(rc)) + if (rc < 0) return rc; return len; @@ -674,11 +696,11 @@ ssize_t nvmem_device_cell_read(struct nvmem_device *nvmem, return -EINVAL; rc = nvmem_cell_info_to_nvmem_cell(nvmem, info, &cell); - if (IS_ERR_VALUE(rc)) + if (rc < 0) return rc; rc = __nvmem_cell_read(nvmem, &cell, buf, &len); - if (IS_ERR_VALUE(rc)) + if (rc < 0) return rc; return len; @@ -704,7 +726,7 @@ int nvmem_device_cell_write(struct nvmem_device *nvmem, return -EINVAL; rc = nvmem_cell_info_to_nvmem_cell(nvmem, info, &cell); - if (IS_ERR_VALUE(rc)) + if (rc < 0) return rc; return nvmem_cell_write(&cell, buf, cell.bytes); @@ -737,9 +759,9 @@ int nvmem_device_read(struct nvmem_device *nvmem, if (!bytes) return 0; - rc = nvmem->bus->read(nvmem->priv, offset, buf, bytes); + rc = nvmem->reg_read(nvmem->priv, offset, buf, bytes); - if (IS_ERR_VALUE(rc)) + if (rc < 0) return rc; return bytes; @@ -771,9 +793,9 @@ int nvmem_device_write(struct nvmem_device *nvmem, if (!bytes) return 0; - rc = nvmem->bus->write(nvmem->priv, offset, buf, bytes); + rc = nvmem->reg_write(nvmem->priv, offset, buf, bytes); - if (IS_ERR_VALUE(rc)) + if (rc < 0) return rc; @@ -803,3 +825,42 @@ void *nvmem_cell_get_and_read(struct device_node *np, const char *cell_name, return value; } EXPORT_SYMBOL_GPL(nvmem_cell_get_and_read); + +/** + * nvmem_cell_read_variable_le_u32() - Read up to 32-bits of data as a little endian number. + * + * @dev: Device that requests the nvmem cell. + * @cell_id: Name of nvmem cell to read. + * @val: pointer to output value. + * + * Return: 0 on success or negative errno. + */ +int nvmem_cell_read_variable_le_u32(struct device *dev, const char *cell_id, + u32 *val) +{ + size_t len; + const u8 *buf; + int i; + + len = sizeof(*val); + + buf = nvmem_cell_get_and_read(dev->of_node, cell_id, len); + if (IS_ERR(buf)) + return PTR_ERR(buf); + + /* Copy w/ implicit endian conversion */ + *val = 0; + for (i = 0; i < len; i++) + *val |= buf[i] << (8 * i); + + kfree(buf); + + return 0; +} +EXPORT_SYMBOL_GPL(nvmem_cell_read_variable_le_u32); + +struct device *nvmem_device_get_device(struct nvmem_device *nvmem) +{ + return &nvmem->dev; +} +EXPORT_SYMBOL_GPL(nvmem_device_get_device); |