From: Shivendra Pratap <shivendra.pratap@oss.qualcomm.com>
To: Bartosz Golaszewski <brgl@kernel.org>
Cc: linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-arm-msm@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org,
Florian Fainelli <florian.fainelli@broadcom.com>,
Krzysztof Kozlowski <krzk@kernel.org>,
Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>,
Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>,
Andre Draszik <andre.draszik@linaro.org>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
Kathiravan Thirumoorthy
<kathiravan.thirumoorthy@oss.qualcomm.com>,
mfd@lists.linux.dev, Srinivas Kandagatla <srini@kernel.org>,
Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>,
Sebastian Reichel <sre@kernel.org>,
Mark Rutland <mark.rutland@arm.com>,
Lorenzo Pieralisi <lpieralisi@kernel.org>,
"Rafael J. Wysocki" <rafael@kernel.org>,
Daniel Lezcano <daniel.lezcano@kernel.org>,
Christian Loehle <christian.loehle@arm.com>,
Ulf Hansson <ulfh@kernel.org>, Lee Jones <lee@kernel.org>,
Rob Herring <robh@kernel.org>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>,
Bjorn Andersson <andersson@kernel.org>,
Konrad Dybcio <konradybcio@kernel.org>,
Arnd Bergmann <arnd@arndb.de>,
Souvik Chakravarty <Souvik.Chakravarty@arm.com>,
Andy Yan <andy.yan@rock-chips.com>,
Matthias Brugger <matthias.bgg@gmail.com>,
John Stultz <john.stultz@linaro.org>,
Moritz Fischer <moritz.fischer@ettus.com>,
Sudeep Holla <sudeep.holla@kernel.org>
Subject: Re: [PATCH v23 08/13] mfd: core: Add firmware-node support to MFD cells
Date: Tue, 21 Jul 2026 18:18:46 +0530 [thread overview]
Message-ID: <c7f5d4cf-07ee-4716-bb8d-83bcd0b2f8d0@oss.qualcomm.com> (raw)
In-Reply-To: <CAMRc=McxoC6711rmXmPb9t21bBsTeBMJ3ieZ1XhyTqMLaMS-4Q@mail.gmail.com>
On 21-07-2026 14:59, Bartosz Golaszewski wrote:
> On Tue, 14 Jul 2026 19:16:36 +0200, Shivendra Pratap
> <shivendra.pratap@oss.qualcomm.com> said:
>> 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 named firmware-node field to identify a
>> child node under the MFD parent. 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@oss.qualcomm.com>
>> Signed-off-by: Shivendra Pratap <shivendra.pratap@oss.qualcomm.com>
>> ---
>> drivers/mfd/mfd-core.c | 142 ++++++++++++++++++++++++++++++++++++++++-------
>> include/linux/mfd/core.h | 10 ++++
>> 2 files changed, 131 insertions(+), 21 deletions(-)
>>
>> diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
>> index 7aa32b90cf1e..ba9682ead2ca 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>
>> @@ -22,6 +23,7 @@
>> #include <linux/regulator/consumer.h>
>>
>> static LIST_HEAD(mfd_of_node_list);
>> +static LIST_HEAD(mfd_named_fwnode_list);
>> static DEFINE_MUTEX(mfd_of_node_mutex);
>>
>> struct mfd_of_node_entry {
>> @@ -30,10 +32,91 @@ struct mfd_of_node_entry {
>> struct device_node *np;
>> };
>>
>> +struct mfd_named_fwnode_entry {
>> + struct list_head list;
>> + struct device *dev;
>> + struct fwnode_handle *fwnode;
>> +};
>> +
>> static const struct device_type mfd_dev_type = {
>> .name = "mfd_device",
>> };
>>
>> +static int mfd_claim_named_fwnode(struct platform_device *pdev,
>> + struct fwnode_handle *fwnode)
>> +{
>> + struct mfd_named_fwnode_entry *entry, *iter;
>> +
>> + entry = kzalloc_obj(*entry, GFP_KERNEL);
>> + if (!entry)
>> + return -ENOMEM;
>> +
>> + entry->dev = &pdev->dev;
>> + entry->fwnode = fwnode_handle_get(fwnode);
>> +
>> + scoped_guard(mutex, &mfd_of_node_mutex) {
>> + list_for_each_entry(iter, &mfd_named_fwnode_list, list)
>> + if (iter->fwnode == fwnode) {
>> + fwnode_handle_put(entry->fwnode);
>> + kfree(entry);
>> + return -EAGAIN;
>> + }
>> +
>> + list_add_tail(&entry->list, &mfd_named_fwnode_list);
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +/*
>> + * Temporary MFD-local cleanup for named non-OF child fwnodes.
>> + * Remove/rework this when platform core starts owning and dropping
>> + * dev->fwnode references for these devices.
>> + */
>> +static void mfd_release_named_fwnode(struct platform_device *pdev)
>> +{
>> + struct mfd_named_fwnode_entry *entry, *tmp;
>> +
>> + scoped_guard(mutex, &mfd_of_node_mutex) {
>> + list_for_each_entry_safe(entry, tmp, &mfd_named_fwnode_list, list)
>> + if (entry->dev == &pdev->dev) {
>> + if (dev_fwnode(&pdev->dev) == entry->fwnode)
>> + device_set_node(&pdev->dev, NULL);
>> + fwnode_handle_put(entry->fwnode);
>> + list_del(&entry->list);
>> + kfree(entry);
>> + }
>> + }
>> +}
>> +
>> +static int mfd_claim_of_node_to_dev(struct platform_device *pdev,
>> + struct device_node *np)
>> +{
>> + struct mfd_of_node_entry *of_entry, *iter;
>> +
>> + of_entry = kzalloc_obj(*of_entry, GFP_KERNEL);
>> + if (!of_entry)
>> + return -ENOMEM;
>> +
>> + of_entry->dev = &pdev->dev;
>> + of_entry->np = of_node_get(np);
>> +
>> + /* Skip if OF node has previously been allocated to a device */
>> + scoped_guard(mutex, &mfd_of_node_mutex) {
>> + list_for_each_entry(iter, &mfd_of_node_list, list)
>> + if (iter->np == np) {
>> + of_node_put(of_entry->np);
>> + kfree(of_entry);
>> + return -EAGAIN;
>> + }
>> +
>> + list_add_tail(&of_entry->list, &mfd_of_node_list);
>> + }
>> +
>> + device_set_node(&pdev->dev, of_fwnode_handle(np));
>> + return 0;
>> +}
>> +
>> #if IS_ENABLED(CONFIG_ACPI)
>> struct match_ids_walk_data {
>> struct acpi_device_id *ids;
>> @@ -111,19 +194,11 @@ static int mfd_match_of_node_to_dev(struct platform_device *pdev,
>> struct device_node *np,
>> const struct mfd_cell *cell)
>> {
>> - struct mfd_of_node_entry *of_entry;
>> u64 of_node_addr;
>>
>> - /* Skip if OF node has previously been allocated to a device */
>> - scoped_guard(mutex, &mfd_of_node_mutex) {
>> - list_for_each_entry(of_entry, &mfd_of_node_list, list)
>> - if (of_entry->np == np)
>> - return -EAGAIN;
>> - }
>> -
>> if (!cell->use_of_reg)
>> /* No of_reg defined - allocate first free compatible match */
>> - goto allocate_of_node;
>> + return mfd_claim_of_node_to_dev(pdev, np);
>>
>> /* We only care about each node's first defined address */
>> if (of_property_read_reg(np, 0, &of_node_addr, NULL))
>> @@ -134,18 +209,7 @@ static int mfd_match_of_node_to_dev(struct platform_device *pdev,
>> /* No match */
>> return -EAGAIN;
>>
>> -allocate_of_node:
>> - of_entry = kzalloc(sizeof(*of_entry), GFP_KERNEL);
>> - if (!of_entry)
>> - return -ENOMEM;
>> -
>> - of_entry->dev = &pdev->dev;
>> - of_entry->np = of_node_get(np);
>> - scoped_guard(mutex, &mfd_of_node_mutex)
>> - list_add_tail(&of_entry->list, &mfd_of_node_list);
>> -
>> - device_set_node(&pdev->dev, of_fwnode_handle(np));
>> - return 0;
>> + return mfd_claim_of_node_to_dev(pdev, np);
>> }
>>
>> static int mfd_add_device(struct device *parent, int id,
>> @@ -156,6 +220,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 +289,37 @@ static int mfd_add_device(struct device *parent, int id,
>>
>> mfd_acpi_add_device(cell, pdev);
>>
>> + /* named_fwnode is a fallback only when no OF/ACPI match and no swnode */
>> + if (!pdev->dev.fwnode && !cell->swnode && cell->named_fwnode) {
>
> Use dev_fwnode() instead of pdev->dev.fwnode.
sure will update. thanks.
>
>> + struct device_node *named_np;
>> +
>> + fwnode = device_get_named_child_node(parent, cell->named_fwnode);
>> + if (!fwnode) {
>> + ret = -ENODEV;
>> + goto fail_alias;
>> + }
>> +
>> + named_np = to_of_node(fwnode);
>> + if (named_np) {
>> + ret = mfd_claim_of_node_to_dev(pdev, named_np);
>> + fwnode_handle_put(fwnode);
>> + if (ret == -EAGAIN)
>> + ret = -EBUSY;
>> + if (ret)
>> + goto fail_alias;
>> + } else {
>> + ret = mfd_claim_named_fwnode(pdev, fwnode);
>> + if (ret) {
>> + fwnode_handle_put(fwnode);
>> + if (ret == -EAGAIN)
>> + ret = -EBUSY;
>> + goto fail_alias;
>> + }
>> + device_set_node(&pdev->dev, fwnode);
>> + fwnode_handle_put(fwnode);
>> + }
>
> What is the reason to have this split into OF and fwnode functions? I don't
> really see why you would need to do it twice, isn't fwnode sufficient for the
> OF node case too?
We do a duplicate check here before adding the named_fwnode and split it
for two reasons:
1. of_node list pre-exists. We add a new list of fwnode. of_node based
duplicate check go wrong, if its checked with the fwnode list.
2. of_node need to go to its respective list as fwnode list, release
path, is different for us.
>
>> + }
>> +
>> if (cell->pdata_size) {
>> ret = platform_device_add_data(pdev,
>> cell->platform_data, cell->pdata_size);
>> @@ -295,6 +391,7 @@ static int mfd_add_device(struct device *parent, int id,
>> if (cell->swnode)
>> device_remove_software_node(&pdev->dev);
>> fail_of_entry:
>> + mfd_release_named_fwnode(pdev);
>> scoped_guard(mutex, &mfd_of_node_mutex) {
>> list_for_each_entry_safe(of_entry, tmp, &mfd_of_node_list, list)
>> if (of_entry->dev == &pdev->dev) {
>> @@ -382,7 +479,10 @@ static int mfd_remove_devices_fn(struct device *dev, void *data)
>> regulator_bulk_unregister_supply_alias(dev, cell->parent_supplies,
>> cell->num_parent_supplies);
>>
>> + get_device(&pdev->dev);
>> platform_device_unregister(pdev);
>> + mfd_release_named_fwnode(pdev);
>> + put_device(&pdev->dev);
>> return 0;
>> }
>>
>> diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h
>> index faeea7abd688..8daa83dd31ea 100644
>> --- a/include/linux/mfd/core.h
>> +++ b/include/linux/mfd/core.h
>> @@ -80,6 +80,16 @@ struct mfd_cell {
>>
>> /* Software node for the device. */
>> const struct software_node *swnode;
>> + /*
>> + * Name of a child firmware node under the MFD parent device.
>> + *
>> + * Used only as a fallback when no firmware node is assigned to MFD
>> + * child and no software node is provided.
>> + *
>> + * For Device Tree parents, lookup is by base node name only
>> + * (the part before '@'). Unit-addresses are not matched.
>> + */
>
> Side note: struct mfd_cell could really use a proper kernel doc but that's out
> of scope of this series.
>
>> + const char *named_fwnode;
>>
>> /*
>> * Device Tree compatible string
>>
>> --
>> 2.34.1
>>
>>
>
> Bartosz
thanks,
Shivendra
next prev parent reply other threads:[~2026-07-21 12:49 UTC|newest]
Thread overview: 38+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-14 17:16 [PATCH v23 00/13] Implement PSCI reboot mode driver for PSCI resets Shivendra Pratap
2026-07-14 17:16 ` [PATCH v23 01/13] power: reset: reboot-mode: Remove devres based allocations Shivendra Pratap
2026-07-21 18:00 ` Pavan Kondeti
2026-07-22 6:09 ` Shivendra Pratap
2026-07-14 17:16 ` [PATCH v23 02/13] power: reset: reboot-mode: Support up to 3 magic values per mode Shivendra Pratap
2026-07-15 12:26 ` Bartosz Golaszewski
2026-07-15 12:32 ` Shivendra Pratap
2026-07-22 9:50 ` Pavan Kondeti
2026-07-22 13:33 ` Shivendra Pratap
2026-07-23 10:03 ` Pavan Kondeti
2026-07-14 17:16 ` [PATCH v23 03/13] power: reset: reboot-mode: Add support for predefined reboot modes Shivendra Pratap
2026-07-22 7:40 ` Pavan Kondeti
2026-07-23 13:09 ` Shivendra Pratap
2026-07-22 9:04 ` Pavan Kondeti
2026-07-23 13:14 ` Shivendra Pratap
2026-07-14 17:16 ` [PATCH v23 04/13] firmware: psci: Introduce command-based resets Shivendra Pratap
2026-07-22 9:24 ` Pavan Kondeti
2026-07-23 13:29 ` Shivendra Pratap
2026-07-14 17:16 ` [PATCH v23 05/13] mfd: psci-mfd: Add PSCI MFD driver for cpuidle-psci-domain cell Shivendra Pratap
2026-07-14 17:16 ` [PATCH v23 06/13] dt-bindings: arm: Document reboot mode magic Shivendra Pratap
2026-07-22 17:11 ` Rob Herring
2026-07-23 13:33 ` Shivendra Pratap
2026-07-14 17:16 ` [PATCH v23 07/13] power: reset: Add psci-reboot-mode driver Shivendra Pratap
2026-07-15 13:10 ` Bartosz Golaszewski
2026-07-22 9:00 ` Pavan Kondeti
2026-07-23 13:31 ` Shivendra Pratap
2026-07-14 17:16 ` [PATCH v23 08/13] mfd: core: Add firmware-node support to MFD cells Shivendra Pratap
2026-07-21 9:29 ` Bartosz Golaszewski
2026-07-21 12:48 ` Shivendra Pratap [this message]
2026-07-22 10:01 ` Bartosz Golaszewski
2026-07-14 17:16 ` [PATCH v23 09/13] mfd: psci-mfd: Add psci-reboot-mode child cell Shivendra Pratap
2026-07-15 13:14 ` Bartosz Golaszewski
2026-07-15 13:28 ` Shivendra Pratap
2026-07-14 17:16 ` [PATCH v23 10/13] arm64: dts: qcom: Add psci reboot-modes for kodiak boards Shivendra Pratap
2026-07-14 17:16 ` [PATCH v23 11/13] arm64: dts: qcom: Add psci reboot-modes for lemans boards Shivendra Pratap
2026-07-14 17:16 ` [PATCH v23 12/13] arm64: dts: qcom: Add psci reboot-modes for monaco boards Shivendra Pratap
2026-07-14 17:16 ` [PATCH v23 13/13] arm64: dts: qcom: Add psci reboot-modes for talos boards Shivendra Pratap
2026-07-15 12:27 ` [PATCH v23 00/13] Implement PSCI reboot mode driver for PSCI resets Bartosz Golaszewski
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=c7f5d4cf-07ee-4716-bb8d-83bcd0b2f8d0@oss.qualcomm.com \
--to=shivendra.pratap@oss.qualcomm.com \
--cc=Souvik.Chakravarty@arm.com \
--cc=andersson@kernel.org \
--cc=andre.draszik@linaro.org \
--cc=andy.yan@rock-chips.com \
--cc=arnd@arndb.de \
--cc=bartosz.golaszewski@oss.qualcomm.com \
--cc=brgl@kernel.org \
--cc=christian.loehle@arm.com \
--cc=conor+dt@kernel.org \
--cc=daniel.lezcano@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=dmitry.baryshkov@oss.qualcomm.com \
--cc=florian.fainelli@broadcom.com \
--cc=gregkh@linuxfoundation.org \
--cc=john.stultz@linaro.org \
--cc=kathiravan.thirumoorthy@oss.qualcomm.com \
--cc=konradybcio@kernel.org \
--cc=krzk+dt@kernel.org \
--cc=krzk@kernel.org \
--cc=lee@kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pm@vger.kernel.org \
--cc=lpieralisi@kernel.org \
--cc=mark.rutland@arm.com \
--cc=matthias.bgg@gmail.com \
--cc=mfd@lists.linux.dev \
--cc=moritz.fischer@ettus.com \
--cc=mukesh.ojha@oss.qualcomm.com \
--cc=rafael@kernel.org \
--cc=robh@kernel.org \
--cc=sre@kernel.org \
--cc=srini@kernel.org \
--cc=sudeep.holla@kernel.org \
--cc=ulfh@kernel.org \
/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