[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250314113604.1776201-6-o.rempel@pengutronix.de>
Date: Fri, 14 Mar 2025 12:36:02 +0100
From: Oleksij Rempel <o.rempel@...gutronix.de>
To: Sebastian Reichel <sre@...nel.org>,
Srinivas Kandagatla <srinivas.kandagatla@...aro.org>,
Benson Leung <bleung@...omium.org>,
Tzung-Bi Shih <tzungbi@...nel.org>,
Daniel Lezcano <daniel.lezcano@...aro.org>
Cc: Oleksij Rempel <o.rempel@...gutronix.de>,
kernel@...gutronix.de,
linux-kernel@...r.kernel.org,
Liam Girdwood <lgirdwood@...il.com>,
Mark Brown <broonie@...nel.org>,
"Rafael J. Wysocki" <rafael@...nel.org>,
Zhang Rui <rui.zhang@...el.com>,
Lukasz Luba <lukasz.luba@....com>,
linux-pm@...r.kernel.org,
Søren Andersen <san@...v.dk>,
Guenter Roeck <groeck@...omium.org>,
Matti Vaittinen <mazziesaccount@...il.com>,
Ahmad Fatoum <a.fatoum@...gutronix.de>,
Andrew Morton <akpm@...ux-foundation.org>,
chrome-platform@...ts.linux.dev
Subject: [PATCH v6 5/7] nvmem: add support for device and sysfs-based cell lookups
Introduce new API functions to allow looking up NVMEM devices and cells
by name, enhancing flexibility in cases where devicetree-based lookup
is not available.
Key changes:
- Added `nvmem_device_get_by_name()`: Enables retrieving an NVMEM device by
its name for systems where direct device reference is needed.
- Added `nvmem_cell_get_by_sysfs_name()`: Allows retrieving an NVMEM cell
based on its sysfs-style name (e.g., "cell@...set,bits"), making it
possible to identify cells dynamically.
- Introduced `nvmem_find_cell_entry_by_sysfs_name()`: A helper function
that constructs sysfs-like names and searches for matching cell entries.
Signed-off-by: Oleksij Rempel <o.rempel@...gutronix.de>
---
changes v5:
- fix build we NVMEM=n
---
drivers/nvmem/core.c | 105 +++++++++++++++++++++++++++++++++
include/linux/nvmem-consumer.h | 18 ++++++
2 files changed, 123 insertions(+)
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index 754a9448c39d..676b2308f62f 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -1203,6 +1203,23 @@ struct nvmem_device *of_nvmem_device_get(struct device_node *np, const char *id)
EXPORT_SYMBOL_GPL(of_nvmem_device_get);
#endif
+/**
+ * nvmem_device_get_by_name - Look up an NVMEM device by its device name
+ * @name: String matching device name in the provider
+ *
+ * Return: A valid pointer to struct nvmem_device on success,
+ * or ERR_PTR(...) on failure. The caller must later call nvmem_device_put() to
+ * release the reference.
+ */
+struct nvmem_device *nvmem_device_get_by_name(const char *name)
+{
+ if (!name)
+ return ERR_PTR(-EINVAL);
+
+ return __nvmem_device_get((void *)name, device_match_name);
+}
+EXPORT_SYMBOL_GPL(nvmem_device_get_by_name);
+
/**
* nvmem_device_get() - Get nvmem device from a given id
*
@@ -1516,6 +1533,94 @@ struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *id)
EXPORT_SYMBOL_GPL(of_nvmem_cell_get);
#endif
+/**
+ * nvmem_find_cell_entry_by_sysfs_name - Find an NVMEM cell entry by its sysfs
+ * name.
+ * @nvmem: The nvmem_device pointer where the cell is located.
+ * @sysfs_name: The full sysfs cell name, e.g. "mycell@...00,8".
+ *
+ * This function constructs the sysfs-like name for each cell and compares it
+ * to @sysfs_name. If a match is found, the matching nvmem_cell_entry pointer
+ * is returned. This is analogous to nvmem_find_cell_entry_by_name(), except
+ * it matches on the sysfs naming convention used in the device's attributes.
+ *
+ * Return: Pointer to the matching nvmem_cell_entry on success, or NULL if no
+ * match is found.
+ */
+static struct nvmem_cell_entry *
+nvmem_find_cell_entry_by_sysfs_name(struct nvmem_device *nvmem,
+ const char *sysfs_name)
+{
+ struct nvmem_cell_entry *entry;
+ char tmp[NVMEM_CELL_NAME_MAX];
+
+ mutex_lock(&nvmem_mutex);
+ list_for_each_entry(entry, &nvmem->cells, node) {
+ int len = snprintf(tmp, NVMEM_CELL_NAME_MAX, "%s@%x,%u",
+ entry->name, entry->offset,
+ entry->bit_offset);
+
+ if (len >= NVMEM_CELL_NAME_MAX) {
+ pr_warn("nvmem: cell name too long (max %zu bytes): %s\n",
+ NVMEM_CELL_NAME_MAX, sysfs_name);
+ continue;
+ }
+
+ if (len < 0) {
+ pr_warn("nvmem: error formatting cell name\n");
+ continue;
+ }
+
+ if (!strcmp(tmp, sysfs_name)) {
+ mutex_unlock(&nvmem_mutex);
+ return entry;
+ }
+ }
+
+ mutex_unlock(&nvmem_mutex);
+ return NULL;
+}
+
+/**
+ * nvmem_cell_get_by_sysfs_name - Retrieve an NVMEM cell using a sysfs-style
+ * name.
+ * @nvmem: Pointer to the `struct nvmem_device` containing the cell.
+ * @sysfs_name: The sysfs-style cell name, formatted as
+ * "<cell_name>@<offset>,<bits>".
+ *
+ * This function enables dynamic lookup of NVMEM cells via sysfs-style
+ * identifiers. It is useful when devicetree-based lookup is unavailable or when
+ * cells are managed dynamically.
+ *
+ * Example Usage:
+ * nvmem_cell_get_by_sysfs_name(nvmem, "mycell@...00,8");
+ *
+ * Return: Pointer to `struct nvmem_cell` on success. On error, an ERR_PTR() is
+ * returned with the appropriate error code.
+ */
+struct nvmem_cell *nvmem_cell_get_by_sysfs_name(struct nvmem_device *nvmem,
+ const char *sysfs_name)
+{
+ struct nvmem_cell_entry *entry;
+ struct nvmem_cell *cell;
+
+ entry = nvmem_find_cell_entry_by_sysfs_name(nvmem, sysfs_name);
+ if (!entry)
+ return ERR_PTR(-ENOENT);
+
+ if (!try_module_get(nvmem->owner))
+ return ERR_PTR(-EINVAL);
+
+ kref_get(&nvmem->refcnt);
+
+ cell = nvmem_create_cell(entry, entry->name, 0);
+ if (IS_ERR(cell))
+ __nvmem_device_put(nvmem);
+
+ return cell;
+}
+EXPORT_SYMBOL_GPL(nvmem_cell_get_by_sysfs_name);
+
/**
* nvmem_cell_get() - Get nvmem cell of device form a given cell name
*
diff --git a/include/linux/nvmem-consumer.h b/include/linux/nvmem-consumer.h
index bcb0e17e415d..2b5e06f457b0 100644
--- a/include/linux/nvmem-consumer.h
+++ b/include/linux/nvmem-consumer.h
@@ -20,6 +20,10 @@ struct nvmem_cell;
struct nvmem_device;
struct nvmem_cell_info;
+#define NVMEM_CELL_NAME_MAX \
+ (sizeof("very_long_cell_name_with_some_extra_chars_12345678@...2345678,128"))
+
+
/**
* struct nvmem_cell_lookup - cell lookup entry
*
@@ -52,6 +56,8 @@ enum {
/* Cell based interface */
struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *id);
struct nvmem_cell *devm_nvmem_cell_get(struct device *dev, const char *id);
+struct nvmem_cell *nvmem_cell_get_by_sysfs_name(struct nvmem_device *nvmem,
+ const char *cell_name);
void nvmem_cell_put(struct nvmem_cell *cell);
void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell);
void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len);
@@ -70,6 +76,7 @@ int nvmem_cell_read_variable_le_u64(struct device *dev, const char *cell_id,
struct nvmem_device *nvmem_device_get(struct device *dev, const char *name);
struct nvmem_device *devm_nvmem_device_get(struct device *dev,
const char *name);
+struct nvmem_device *nvmem_device_get_by_name(const char *name);
void nvmem_device_put(struct nvmem_device *nvmem);
void devm_nvmem_device_put(struct device *dev, struct nvmem_device *nvmem);
int nvmem_device_read(struct nvmem_device *nvmem, unsigned int offset,
@@ -109,6 +116,12 @@ static inline struct nvmem_cell *devm_nvmem_cell_get(struct device *dev,
return ERR_PTR(-EOPNOTSUPP);
}
+static inline struct nvmem_cell *
+nvmem_cell_get_by_sysfs_name(struct nvmem_device *nvmem, const char *cell_name)
+{
+ return ERR_PTR(-EOPNOTSUPP);
+}
+
static inline void devm_nvmem_cell_put(struct device *dev,
struct nvmem_cell *cell)
{
@@ -185,6 +198,11 @@ static inline struct nvmem_device *devm_nvmem_device_get(struct device *dev,
return ERR_PTR(-EOPNOTSUPP);
}
+static inline struct nvmem_device *nvmem_device_get_by_name(const char *name)
+{
+ return ERR_PTR(-EOPNOTSUPP);
+}
+
static inline void nvmem_device_put(struct nvmem_device *nvmem)
{
}
--
2.39.5
Powered by blists - more mailing lists