From: Marco Felsch <m.felsch@pengutronix.de>
To: Sascha Hauer <s.hauer@pengutronix.de>,
BAREBOX <barebox@lists.infradead.org>
Cc: Marco Felsch <m.felsch@pengutronix.de>
Subject: [PATCH 06/15] nvmem: core: expose nvmem cells as cdev
Date: Mon, 04 Aug 2025 16:36:52 +0200 [thread overview]
Message-ID: <20250804-v2025-06-0-topic-nvmem-v1-6-7603eaa4d2b0@pengutronix.de> (raw)
In-Reply-To: <20250804-v2025-06-0-topic-nvmem-v1-0-7603eaa4d2b0@pengutronix.de>
Linux has added the support to expose nvmem-cells via the sysfs by
commit 0331c611949f ("nvmem: core: Expose cells through sysfs"). This
commit adds an equivalent mechanism by exposing the nvmem-cells via
cdevs. The name scheme is: <nvmem-dev-name>.<cell-name>.
With this in place it is possible for board code and/or shell to query
the nvmem-cell values without specifying the consumer API within DT. At
the moment the access is RO like Linux does since write support requires
more corner case handling.
The naming scheme for nvmem_populate_sysfs_cells() was kept to reduce the
Linux diff.
Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
---
drivers/nvmem/core.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 93 insertions(+)
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index c9afbb242f945df8a770b783bb02c8132dc59347..328e2839cc47326de53a5950ffaa676926882c32 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -43,6 +43,8 @@ struct nvmem_cell_entry {
struct device_node *np;
struct nvmem_device *nvmem;
struct list_head node;
+
+ struct cdev cdev;
};
struct nvmem_cell {
@@ -136,6 +138,71 @@ static struct nvmem_device *of_nvmem_find(struct device_node *nvmem_np)
return NULL;
}
+static struct nvmem_cell *nvmem_create_cell(struct nvmem_cell_entry *entry,
+ const char *id, int index);
+
+static ssize_t nvmem_cell_cdev_read(struct cdev *cdev, void *buf, size_t count,
+ loff_t offset, unsigned long flags)
+{
+ struct nvmem_cell_entry *entry;
+ struct nvmem_cell *cell = NULL;
+ size_t cell_sz, read_len;
+ void *content;
+
+ entry = container_of(cdev, struct nvmem_cell_entry, cdev);
+ cell = nvmem_create_cell(entry, entry->name, 0);
+ if (IS_ERR(cell))
+ return PTR_ERR(cell);
+
+ content = nvmem_cell_read(cell, &cell_sz);
+ if (IS_ERR(content)) {
+ read_len = PTR_ERR(content);
+ goto destroy_cell;
+ }
+
+ read_len = min_t(unsigned int, cell_sz - offset, count);
+ memcpy(buf, content + offset, read_len);
+ kfree(content);
+
+destroy_cell:
+ kfree_const(cell->id);
+ kfree(cell);
+
+ return read_len;
+}
+
+static struct cdev_operations nvmem_cell_chrdev_ops = {
+ .read = nvmem_cell_cdev_read,
+};
+
+static int nvmem_populate_sysfs_cells(struct nvmem_device *nvmem)
+{
+ struct device *dev = &nvmem->dev;
+ struct nvmem_cell_entry *entry;
+
+ list_for_each_entry(entry, &nvmem->cells, node) {
+ struct cdev *cdev;
+ int ret;
+
+ cdev = &entry->cdev;
+ cdev->name = xasprintf("%s.%s", dev_name(dev),
+ kbasename(entry->name));
+ cdev->ops = &nvmem_cell_chrdev_ops;
+ cdev->dev = dev;
+ cdev->size = entry->bytes;
+
+ /* Ignore the error but throw a warning for the user */
+ ret = devfs_create(cdev);
+ if (ret) {
+ dev_err(dev, "Failed to register %s with %pe\n",
+ cdev->name, ERR_PTR(ret));
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
static void nvmem_cell_entry_drop(struct nvmem_cell_entry *cell)
{
list_del(&cell->node);
@@ -152,6 +219,26 @@ static void nvmem_device_remove_all_cells(const struct nvmem_device *nvmem)
nvmem_cell_entry_drop(cell);
}
+static void nvmem_device_remove_all_cdevs(struct nvmem_device *nvmem)
+{
+ struct nvmem_cell_entry *cell, *p;
+
+ list_for_each_entry_safe(cell, p, &nvmem->cells, node) {
+ if (cell->cdev.name && cdev_by_name(cell->cdev.name)) {
+ devfs_remove(&cell->cdev);
+ free(cell->cdev.name);
+ cell->cdev.name = NULL;
+ }
+ }
+
+ if (!nvmem->cdev.name)
+ return;
+
+ devfs_remove(&nvmem->cdev);
+ free(nvmem->cdev.name);
+ nvmem->cdev.name = NULL;
+}
+
static void nvmem_cell_entry_add(struct nvmem_cell_entry *cell)
{
list_add_tail(&cell->node, &cell->nvmem->cells);
@@ -338,10 +425,16 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
goto err_unregister;
}
+ rval = nvmem_populate_sysfs_cells(nvmem);
+ if (rval)
+ goto err_remove_cdevs;
+
list_add_tail(&nvmem->node, &nvmem_devs);
return nvmem;
+err_remove_cdevs:
+ nvmem_device_remove_all_cdevs(nvmem);
err_unregister:
unregister_device(&nvmem->dev);
err_remove_cells:
--
2.39.5
next prev parent reply other threads:[~2025-08-04 15:32 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-08-04 14:36 [PATCH 00/15] NVMEM: Add support for layout drivers Marco Felsch
2025-08-04 14:36 ` [PATCH 01/15] of: sync of_*_phandle_with_args with Linux Marco Felsch
2025-08-04 14:36 ` [PATCH 02/15] of: base: add of_parse_phandle_with_optional_args() Marco Felsch
2025-08-04 14:36 ` [PATCH 03/15] of: device: Export of_device_make_bus_id() Marco Felsch
2025-08-04 14:36 ` [PATCH 04/15] nvmem: core: fix nvmem_register error path Marco Felsch
2025-08-04 14:36 ` [PATCH 05/15] nvmem: core: sync with Linux Marco Felsch
2025-08-04 14:36 ` Marco Felsch [this message]
2025-08-04 14:36 ` [PATCH 07/15] nvmem: core: allow single and dynamic device ids Marco Felsch
2025-08-04 14:36 ` [PATCH 08/15] eeprom: at24: fix device name handling Marco Felsch
2025-08-04 14:36 ` [PATCH 09/15] nvmem: core: create a header for internal sharing Marco Felsch
2025-08-04 14:36 ` [PATCH 10/15] nvmem: core: add nvmem-layout support Marco Felsch
2025-08-04 14:36 ` [PATCH 11/15] nvmem: core: add an index parameter to the cell Marco Felsch
2025-08-04 14:36 ` [PATCH 12/15] nvmem: core: add per-cell post processing Marco Felsch
2025-08-04 14:36 ` [PATCH 13/15] nvmem: core: add cell based fixup logic Marco Felsch
2025-08-04 14:37 ` [PATCH 14/15] nvmem: core: provide own priv pointer in post process callback Marco Felsch
2025-08-04 14:37 ` [PATCH 15/15] nvmem: core: drop global cell_post_process Marco Felsch
2025-08-05 10:44 ` [PATCH 00/15] NVMEM: Add support for layout drivers Sascha Hauer
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=20250804-v2025-06-0-topic-nvmem-v1-6-7603eaa4d2b0@pengutronix.de \
--to=m.felsch@pengutronix.de \
--cc=barebox@lists.infradead.org \
--cc=s.hauer@pengutronix.de \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox