[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250306093900.2199442-5-o.rempel@pengutronix.de>
Date: Thu, 6 Mar 2025 10:38:56 +0100
From: Oleksij Rempel <o.rempel@...gutronix.de>
To: Sebastian Reichel <sre@...nel.org>,
Srinivas Kandagatla <srinivas.kandagatla@...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>,
Daniel Lezcano <daniel.lezcano@...aro.org>,
Zhang Rui <rui.zhang@...el.com>,
Lukasz Luba <lukasz.luba@....com>,
linux-pm@...r.kernel.org,
Søren Andersen <san@...v.dk>
Subject: [PATCH v4 4/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>
---
drivers/nvmem/core.c | 91 ++++++++++++++++++++++++++++++++++
include/linux/nvmem-consumer.h | 14 ++++++
2 files changed, 105 insertions(+)
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index 928ac15f04a0..2ff0926dea23 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -1203,6 +1203,20 @@ 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)
+{
+ 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 +1530,83 @@ 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;
+
+ mutex_lock(&nvmem_mutex);
+ list_for_each_entry(entry, &nvmem->cells, node) {
+ /* Reconstruct how the sysfs name is assigned */
+ tmp = kasprintf(GFP_KERNEL, "%s@%x,%u", entry->name,
+ entry->offset, entry->bit_offset);
+ if (!tmp)
+ continue;
+
+ if (!strcmp(tmp, sysfs_name)) {
+ kfree(tmp);
+ mutex_unlock(&nvmem_mutex);
+ return entry;
+ }
+ kfree(tmp);
+ }
+ mutex_unlock(&nvmem_mutex);
+
+ return NULL;
+}
+
+/**
+ * nvmem_cell_get_by_sysfs_name - Get a cell by its sysfs name from a given
+ * nvmem_device.
+ * @nvmem: The nvmem_device pointer where the cell is located.
+ * @sysfs_name: The sysfs-style name, e.g. "mycell@...00,8".
+ *
+ * This function uses nvmem_find_cell_entry_by_sysfs_name() to locate the cell
+ * entry, increments the reference counts for the matching NVMEM device, and
+ * then creates a struct nvmem_cell for the caller.
+ *
+ * Return: On success, a valid pointer to an nvmem_cell. On failure, an
+ * ERR_PTR() encoded error (e.g., -ENOENT if the cell entry is not found).
+ */
+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..6fc12cce8eb2 100644
--- a/include/linux/nvmem-consumer.h
+++ b/include/linux/nvmem-consumer.h
@@ -52,6 +52,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 +72,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 +112,12 @@ static inline struct nvmem_cell *devm_nvmem_cell_get(struct device *dev,
return ERR_PTR(-EOPNOTSUPP);
}
+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 +194,11 @@ static inline struct nvmem_device *devm_nvmem_device_get(struct device *dev,
return ERR_PTR(-EOPNOTSUPP);
}
+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