From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
To: Andrey Smirnov <andrew.smirnov@gmail.com>, linux-kernel@vger.kernel.org
Cc: maxime.ripard@free-electrons.com
Subject: Re: [RESEND RFC 3/3] nvmem: Add 'nvmem-composite' driver
Date: Wed, 2 Mar 2016 13:59:38 +0000 [thread overview]
Message-ID: <56D6F1CA.6020302@linaro.org> (raw)
In-Reply-To: <1456851552-15913-4-git-send-email-andrew.smirnov@gmail.com>
On 01/03/16 16:59, Andrey Smirnov wrote:
> Add 'nvmem-composite' driver which allows to combine multiple chunks of
> various NVMEM cells into a single continuous NVMEM device.
My plan on this feature was add support inside the nvmem_cell_get
itself, this makes the nvmem bindings more inline with bindings like
pinctrl.
Also I still want to keep nvmem simple as it can.
DT would look something like this.
nvmem-provider-a {
cell_a {
reg = <0 2>;
};
};
nvmem-provider-b {
cell_b: cell_c {
reg = <0 1>;
};
};
nvmem-provider-c {
cell_c: cell_c {
reg = <3 2>;
}
};
a-node {
nvmem-cells = <&cell_a &cell_b &cell_c>
nvmem-cell-names = "some-data";
};
thanks,
srini
>
> Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
> ---
> .../devicetree/bindings/nvmem/composite.txt | 44 ++++
> drivers/nvmem/Makefile | 1 +
> drivers/nvmem/composite.c | 225 +++++++++++++++++++++
> 3 files changed, 270 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/nvmem/composite.txt
> create mode 100644 drivers/nvmem/composite.c
>
> diff --git a/Documentation/devicetree/bindings/nvmem/composite.txt b/Documentation/devicetree/bindings/nvmem/composite.txt
> new file mode 100644
> index 0000000..e24cf4b
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/nvmem/composite.txt
> @@ -0,0 +1,44 @@
> += NVMEM cell compositor =
> +
> +This binding is designed to provide a way for a developer to combine
> +portions of other NVMEM cell and acces that data as a signle NVMEM
> +cell using NVMEM consumer API.
> +
> +Required properties:
> +- compatible: should be "nvmem-composite"
> +- layout: specifies which sources comprise data in nvmem device
> + format is "<nvmem-cell-phandle offset size>"
> +
> += Data cells =
> +Are child nodes of nvmem-composite, bindings of which as described in
> +bindings/nvmem/nvmem.txt
> +
> +Example:
> +
> + composite-nvmem {
> + compatible = "nvmem-composite";
> + layout = <&another_cell_a 0 2
> + &another_cell_b 0 1
> + &another_cell_c 3 2>;
> +
> + cell1: cell@0 {
> + reg = <0 5>;
> + };
> + }
> +
> +the result of reading variable cell1 would be:
> +
> +[a[0] a[1] b[0] c[3] c[4]],
> +
> +where a[i], b[i], c[i], represnet i-th bytes of NVMEM cells
> +another_cell_a, another_cell_b and another_cell_c respectively
> +
> += Data consumers =
> +Are device nodes which consume nvmem data cells.
> +
> +Example:
> +
> + a-node {
> + nvmem-cells = <&cell1>;
> + nvmem-cell-names = "some-data";
> + };
> diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
> index 1a1adba..49c0eca 100644
> --- a/drivers/nvmem/Makefile
> +++ b/drivers/nvmem/Makefile
> @@ -19,3 +19,4 @@ nvmem_sunxi_sid-y := sunxi_sid.o
> obj-$(CONFIG_NVMEM_VF610_OCOTP) += nvmem-vf610-ocotp.o
> nvmem-vf610-ocotp-y := vf610-ocotp.o
> obj-y += blob.o
> +obj-y += composite.o
> diff --git a/drivers/nvmem/composite.c b/drivers/nvmem/composite.c
> new file mode 100644
> index 0000000..cf01590
> --- /dev/null
> +++ b/drivers/nvmem/composite.c
> @@ -0,0 +1,225 @@
> +#define DEBUG 1
> +
> +#include <linux/device.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/nvmem-provider.h>
> +#include <linux/nvmem-consumer.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/slab.h>
> +
> +struct nvmem_composite {
> + struct device *dev;
> + struct list_head layout;
> + size_t layout_size;
> +};
> +
> +struct nvmem_composite_item {
> + struct nvmem_cell *cell;
> + unsigned int idx, start, end, size;
> + struct list_head node;
> +};
> +
> +static struct nvmem_composite_item *
> +nvmem_composite_find_first(struct nvmem_composite *ncomp,
> + unsigned int offset)
> +{
> + struct nvmem_composite_item *first;
> + list_for_each_entry(first, &ncomp->layout, node) {
> + /*
> + * Skip all of the irrelevant items that end before our offset
> + */
> + if (first->end > offset)
> + return first;
> + }
> +
> + return NULL;
> +}
> +
> +static int nvmem_composite_read(void *context,
> + const void *reg, size_t reg_size,
> + void *val, size_t val_size)
> +{
> + struct nvmem_composite *ncomp = context;
> + const unsigned int offset = *(u32 *)reg;
> + void *dst = val;
> + size_t residue = val_size;
> + struct nvmem_composite_item *item, *first;
> + uint8_t *data;
> + unsigned int size, chunk, ii;
> +
> +
> + first = item = nvmem_composite_find_first(ncomp, offset);
> + if (!first) {
> + dev_dbg(ncomp->dev, "Invalid offset\n");
> + return -EINVAL;
> + }
> +
> + list_for_each_entry_from(item, &ncomp->layout, node) {
> + /*
> + * If our first read is not located on item boundary
> + * we have to introduce artificial offset
> + */
> + ii = (item == first) ? offset - first->start : 0;
> +
> + data = nvmem_cell_read(item->cell, &size);
> + if (IS_ERR(data)) {
> + dev_dbg(ncomp->dev, "Failed to read nvmem cell\n");
> + return PTR_ERR(data);
> + }
> +
> + chunk = min(residue, item->size - ii);
> + memcpy(dst, &data[item->idx + ii], chunk);
> + kfree(data);
> +
> + dst += chunk;
> + residue -= chunk;
> + }
> +
> + return (residue) ? -EINVAL : 0;
> +}
> +
> +static int nvmem_composite_write(void *context, const void *data,
> + size_t count)
> +{
> + return -ENOTSUPP;
> +}
> +
> +static const struct regmap_bus nvmem_composite_regmap_bus = {
> + .write = nvmem_composite_write,
> + .read = nvmem_composite_read,
> +};
> +
> +static int nvmem_composite_validate_dt(struct device_node *np)
> +{
> + /* FIXME */
> + return 0;
> +}
> +
> +static int nvmem_composite_probe(struct platform_device *pdev)
> +{
> + int i, ret;
> + unsigned int start = 0;
> + unsigned int len;
> + struct device *dev = &pdev->dev;
> + struct device_node *np = dev->of_node;
> + struct nvmem_device *nvmem;
> + struct nvmem_composite *ncomp;
> + struct regmap *map;
> + struct nvmem_composite_item *item;
> + struct nvmem_config nv_cnf = {0};
> + struct regmap_config rm_cnf = {0};
> + const __be32 *addr;
> + unsigned int item_count;
> +
> + ret = nvmem_composite_validate_dt(np);
> + if (ret < 0) {
> + dev_dbg(dev, "Device validation failed\n");
> + return ret;
> + }
> +
> + ncomp = devm_kzalloc(dev, sizeof(*ncomp), GFP_KERNEL);
> + INIT_LIST_HEAD(&ncomp->layout);
> + ncomp->dev = dev;
> +
> + addr = of_get_property(np, "layout", &len);
> + item_count = len / (3 * sizeof(__be32));
> +
> + for (i = 0; i < item_count; i++) {
> + struct device_node *cell_np;
> + uint32_t phandle;
> +
> + item = devm_kzalloc(dev, sizeof(*item), GFP_KERNEL);
> +
> + phandle = be32_to_cpup(addr++);
> + cell_np = of_find_node_by_phandle(phandle);
> + if (!cell_np) {
> + dev_dbg(dev,
> + "Couldn't find nvmem cell by its phandle\n");
> + return -ENOENT;
> + }
> +
> + item->cell = of_nvmem_cell_from_device_node(cell_np);
> + if (IS_ERR(item->cell)) {
> + dev_dbg(dev,
> + "Failed to instantiate nvmem cell from "
> + "a device tree node\n");
> + ret = PTR_ERR(item->cell);
> + goto unwind;
> + }
> +
> + item->start = start;
> + item->idx = be32_to_cpup(addr++);
> + item->size = be32_to_cpup(addr++);
> + item->end = item->size - 1;
> + ncomp->layout_size += item->size;
> + start += item->size;
> +
> + list_add_tail(&item->node, &ncomp->layout);
> + }
> +
> + rm_cnf.reg_bits = 32;
> + rm_cnf.val_bits = 8;
> + rm_cnf.reg_stride = 1;
> + rm_cnf.name = "nvmem-composite";
> + rm_cnf.max_register = ncomp->layout_size - 1;
> +
> + map = devm_regmap_init(dev,
> + &nvmem_composite_regmap_bus,
> + ncomp,
> + &rm_cnf);
> + if (IS_ERR(map)) {
> + dev_dbg(dev, "Failed to initilize regmap\n");
> + return PTR_ERR(map);
> + }
> +
> + nv_cnf.name = "nvmem-composite";
> + nv_cnf.read_only = true;
> + nv_cnf.dev = dev;
> +
> + nvmem = nvmem_register(&nv_cnf);
> + if (IS_ERR(nvmem)) {
> + dev_dbg(dev, "Failed to register 'nvmem' device\n");
> + return PTR_ERR(nvmem);
> + }
> +
> + platform_set_drvdata(pdev, nvmem);
> + return 0;
> +unwind:
> + /* FIXME */
> + return ret;
> +}
> +
> +static int nvmem_composite_remove(struct platform_device *pdev)
> +{
> + struct nvmem_device *nvmem = platform_get_drvdata(pdev);
> +
> + /*
> + FIXME free allocated nvmem cells
> + */
> + return nvmem_unregister(nvmem);
> +}
> +
> +
> +static const struct of_device_id nvmem_composite_dt_ids[] = {
> + { .compatible = "nvmem-composite", },
> + { },
> +};
> +MODULE_DEVICE_TABLE(of, nvmem_composite_dt_ids);
> +
> +static struct platform_driver nvmem_composite_driver = {
> + .probe = nvmem_composite_probe,
> + .remove = nvmem_composite_remove,
> + .driver = {
> + .name = "nvmem-composite",
> + .of_match_table = nvmem_composite_dt_ids,
> + },
> +};
> +module_platform_driver(nvmem_composite_driver);
> +
> +MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>");
> +MODULE_DESCRIPTION("FIXME");
> +MODULE_LICENSE("GPL v2");
>
next prev parent reply other threads:[~2016-03-02 13:59 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-03-01 16:59 [RESEND RFC 0/3] Proposed extensions for NVMEM Andrey Smirnov
2016-03-01 16:59 ` [RESEND RFC 1/3] nvmem: Add 'of_nvmem_cell_from_device_node()' Andrey Smirnov
2016-03-02 13:58 ` Srinivas Kandagatla
2016-03-02 18:11 ` Andrey Smirnov
2016-03-01 16:59 ` [RESEND RFC 2/3] nvmem: Add 'nvmem-blob' driver Andrey Smirnov
2016-03-02 13:58 ` Srinivas Kandagatla
2016-03-02 17:21 ` Andrey Smirnov
2016-03-07 8:18 ` Maxime Ripard
2016-03-08 4:07 ` Andrey Smirnov
2016-03-08 22:28 ` Maxime Ripard
2016-03-08 22:46 ` Andrey Smirnov
2016-03-08 23:24 ` Trent Piepho
2016-03-09 10:13 ` Maxime Ripard
2016-03-09 19:50 ` Trent Piepho
2016-03-09 9:58 ` Maxime Ripard
2016-03-09 17:04 ` Andrey Smirnov
2016-03-09 7:59 ` Sascha Hauer
2016-03-01 16:59 ` [RESEND RFC 3/3] nvmem: Add 'nvmem-composite' driver Andrey Smirnov
2016-03-02 13:59 ` Srinivas Kandagatla [this message]
2016-03-02 18:33 ` Andrey Smirnov
2016-03-17 11:26 ` Srinivas Kandagatla
2016-03-21 16:12 ` Andrey Smirnov
2016-03-21 16:56 ` Srinivas Kandagatla
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=56D6F1CA.6020302@linaro.org \
--to=srinivas.kandagatla@linaro.org \
--cc=andrew.smirnov@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=maxime.ripard@free-electrons.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.