@@ -21,6 +21,13 @@ config NVMEM_SYSFS
This interface is mostly used by userspace applications to
read/write directly into nvmem.
+config NVMEM_TRANSFORMATIONS
+ bool "Support cell transformations"
+ help
+ Say Y to support to expand one NVMEM cell into multiple values. For
+ example, when the NVMEM cell stores a base MAC address and it should
+ be expanded to be used for multiple network adapters.
+
config NVMEM_IMX_IIM
tristate "i.MX IC Identification Module support"
depends on ARCH_MXC || COMPILE_TEST
@@ -5,6 +5,7 @@
obj-$(CONFIG_NVMEM) += nvmem_core.o
nvmem_core-y := core.o
+nvmem_core-$(CONFIG_NVMEM_TRANSFORMATIONS) += transformations.o
# Devices
obj-$(CONFIG_NVMEM_BCM_OCOTP) += nvmem-bcm-ocotp.o
@@ -838,6 +838,13 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
}
}
+ /*
+ * Transformations are using the same post process hook, therefore they
+ * are mutually exclusive.
+ */
+ if (!nvmem->cell_post_process)
+ nvmem->cell_post_process = nvmem_get_transformations(nvmem->dev.of_node);
+
dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name);
rval = device_register(&nvmem->dev);
new file mode 100644
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * nvmem cell transformations
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/nvmem-provider.h>
+#include <linux/of.h>
+
+struct nvmem_transformations {
+ const char *compatible;
+ nvmem_cell_post_process_t pp;
+};
+
+static const struct nvmem_transformations nvmem_transformations[] = {
+ {}
+};
+
+nvmem_cell_post_process_t nvmem_get_transformations(struct device_node *np)
+{
+ const struct nvmem_transformations *transform = nvmem_transformations;
+
+ for (; transform->compatible; transform++)
+ if (of_device_is_compatible(np, transform->compatible))
+ return transform->pp;
+
+ return NULL;
+}
@@ -138,6 +138,15 @@ int devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem);
void nvmem_add_cell_table(struct nvmem_cell_table *table);
void nvmem_del_cell_table(struct nvmem_cell_table *table);
+#if IS_ENABLED(CONFIG_NVMEM_TRANSFORMATIONS)
+nvmem_cell_post_process_t nvmem_get_transformations(struct device_node *np);
+#else
+static inline nvmem_cell_post_process_t nvmem_get_transformations(struct device_node *np)
+{
+ return NULL;
+}
+#endif
+
#else
static inline struct nvmem_device *nvmem_register(const struct nvmem_config *c)
Sometimes the value of an nvmem cell must be transformed. For example, a MAC address might be stored in ASCII representation or we might need to swap bytes. We might also want to expand one value to mutliple ones, for example, the nvmem cell might just store a base MAC address to which we need to add an offset to get an address for different network interfaces. Add initial support to add such transformations based on the device tree compatible string of the NVMEM device. It will reuse the nvmem post process hook. Both are mutually exclusive. Signed-off-by: Michael Walle <michael@walle.cc> --- drivers/nvmem/Kconfig | 7 +++++++ drivers/nvmem/Makefile | 1 + drivers/nvmem/core.c | 7 +++++++ drivers/nvmem/transformations.c | 28 ++++++++++++++++++++++++++++ include/linux/nvmem-provider.h | 9 +++++++++ 5 files changed, 52 insertions(+) create mode 100644 drivers/nvmem/transformations.c