[PATCH v22 08/13] mfd: core: Add firmware-node support to MFD cells
Shivendra Pratap
shivendra.pratap at oss.qualcomm.com
Thu May 14 07:25:49 PDT 2026
MFD core has no way to register a child device using an explicit firmware
node. This prevents drivers from registering child nodes when those nodes
do not define a compatible string. One such example is the PSCI
"reboot-mode" node, which omits a compatible string as it describes
boot-states provided by the underlying firmware.
Extend struct mfd_cell with a callback that allows drivers to provide an
explicit firmware node. The node is added to the MFD child device during
registration when none is assigned by device tree, ACPI, or software
matching.
Suggested-by: Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>
Signed-off-by: Shivendra Pratap <shivendra.pratap at oss.qualcomm.com>
---
drivers/mfd/mfd-core.c | 30 ++++++++++++++++++++++++++++++
include/linux/mfd/core.h | 14 ++++++++++++++
2 files changed, 44 insertions(+)
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
index 7aa32b90cf1eb7fa0a05bf3dc506e60a262c9850..cc2a2a924d6d3044e29a9f864b536ee325ed797b 100644
--- a/drivers/mfd/mfd-core.c
+++ b/drivers/mfd/mfd-core.c
@@ -10,6 +10,7 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/acpi.h>
+#include <linux/fwnode.h>
#include <linux/list.h>
#include <linux/property.h>
#include <linux/mfd/core.h>
@@ -148,6 +149,11 @@ static int mfd_match_of_node_to_dev(struct platform_device *pdev,
return 0;
}
+static void mfd_child_fwnode_put(void *data)
+{
+ fwnode_handle_put(data);
+}
+
static int mfd_add_device(struct device *parent, int id,
const struct mfd_cell *cell,
struct resource *mem_base,
@@ -156,6 +162,7 @@ static int mfd_add_device(struct device *parent, int id,
struct resource *res;
struct platform_device *pdev;
struct mfd_of_node_entry *of_entry, *tmp;
+ struct fwnode_handle *fwnode;
bool disabled = false;
int ret = -ENOMEM;
int platform_id;
@@ -224,6 +231,29 @@ static int mfd_add_device(struct device *parent, int id,
mfd_acpi_add_device(cell, pdev);
+ if (!pdev->dev.fwnode && cell->get_child_fwnode) {
+ fwnode = cell->get_child_fwnode(parent);
+ if (fwnode) {
+ device_set_node(&pdev->dev, fwnode);
+
+ /*
+ * platform_device_release() drops only of_node refs.
+ * Track non-OF fwnodes explicitly so they are put on
+ * all teardown paths.
+ */
+ if (!to_of_node(fwnode)) {
+ ret = devm_add_action(&pdev->dev,
+ mfd_child_fwnode_put,
+ fwnode);
+ if (ret) {
+ device_set_node(&pdev->dev, NULL);
+ fwnode_handle_put(fwnode);
+ goto fail_of_entry;
+ }
+ }
+ }
+ }
+
if (cell->pdata_size) {
ret = platform_device_add_data(pdev,
cell->platform_data, cell->pdata_size);
diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h
index faeea7abd688f223fb0b31cde0a9b69dfe2a61ff..abfc26c057d6ee46947ba2b6f2e99f420e74b127 100644
--- a/include/linux/mfd/core.h
+++ b/include/linux/mfd/core.h
@@ -50,6 +50,7 @@
#define MFD_DEP_LEVEL_HIGH 1
struct irq_domain;
+struct fwnode_handle;
struct software_node;
/* Matches ACPI PNP id, either _HID or _CID, or ACPI _ADR */
@@ -80,6 +81,19 @@ struct mfd_cell {
/* Software node for the device. */
const struct software_node *swnode;
+ /*
+ * Callback to return an explicit firmware node.
+ * @parent: MFD parent device passed to mfd_add_devices().
+ *
+ * Called only if OF/ACPI matching did not assign a fwnode.
+ * Ownership of the returned reference is transferred to MFD core.
+ *
+ * Return a referenced fwnode or NULL if none is available.
+ *
+ * mfd_cell must be zero-initialized or get_child_fwnode must be NULL
+ * when unused.
+ */
+ struct fwnode_handle *(*get_child_fwnode)(struct device *parent);
/*
* Device Tree compatible string
--
2.34.1
More information about the linux-arm-kernel
mailing list