I would like the "nxp,sja1110a" driver, in the configuration below, to
be able to probe the drivers for "nxp,sja1110-base-t1-mdio" and for
"nxp,sja1110-base-tx-mdio" via mfd_add_devices():
ethernet-switch@0 {
compatible = "nxp,sja1110a";
mdios {
mdio@0 {
compatible = "nxp,sja1110-base-t1-mdio";
};
mdio@1 {
compatible = "nxp,sja1110-base-tx-mdio";
};
};
};
This isn't currently possible, because mfd assumes that the parent
OF node ("mdios") == OF node of the parent ("ethernet-switch@0"), which
in this case isn't true, and as it searches through the children of
"ethernet-switch@0", it finds no MDIO bus to probe.
Cc: Lee Jones <lee@kernel.org>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
drivers/mfd/mfd-core.c | 11 +++++++++--
include/linux/mfd/core.h | 7 +++++++
2 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
index 7d14a1e7631e..e0b7f93a2654 100644
--- a/drivers/mfd/mfd-core.c
+++ b/drivers/mfd/mfd-core.c
@@ -181,8 +181,14 @@ static int mfd_add_device(struct device *parent, int id,
if (ret < 0)
goto fail_res;
- if (IS_ENABLED(CONFIG_OF) && parent->of_node && cell->of_compatible) {
- for_each_child_of_node(parent->of_node, np) {
+ if (IS_ENABLED(CONFIG_OF)) {
+ const struct device_node *parent_of_node;
+
+ parent_of_node = cell->parent_of_node ?: parent->of_node;
+ if (!parent_of_node || !cell->of_compatible)
+ goto skip_of;
+
+ for_each_child_of_node(parent_of_node, np) {
if (of_device_is_compatible(np, cell->of_compatible)) {
/* Skip 'disabled' devices */
if (!of_device_is_available(np)) {
@@ -213,6 +219,7 @@ static int mfd_add_device(struct device *parent, int id,
cell->name, platform_id);
}
+skip_of:
mfd_acpi_add_device(cell, pdev);
if (cell->pdata_size) {
diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h
index faeea7abd688..2e94ea376125 100644
--- a/include/linux/mfd/core.h
+++ b/include/linux/mfd/core.h
@@ -81,6 +81,13 @@ struct mfd_cell {
/* Software node for the device. */
const struct software_node *swnode;
+ /*
+ * Parent OF node of the device, if different from the OF node
+ * of the MFD parent (e.g. there is at least one more hierarchical
+ * level between them)
+ */
+ const struct device_node *parent_of_node;
+
/*
* Device Tree compatible string
* See: Documentation/devicetree/usage-model.rst Chapter 2.2 for details
--
2.34.1
On Tue, 18 Nov 2025, Vladimir Oltean wrote:
> I would like the "nxp,sja1110a" driver, in the configuration below, to
> be able to probe the drivers for "nxp,sja1110-base-t1-mdio" and for
> "nxp,sja1110-base-tx-mdio" via mfd_add_devices():
>
> ethernet-switch@0 {
> compatible = "nxp,sja1110a";
>
> mdios {
> mdio@0 {
> compatible = "nxp,sja1110-base-t1-mdio";
> };
>
> mdio@1 {
> compatible = "nxp,sja1110-base-tx-mdio";
> };
> };
> };
This device is not an MFD.
Please find a different way to instantiate these network drivers.
> This isn't currently possible, because mfd assumes that the parent
> OF node ("mdios") == OF node of the parent ("ethernet-switch@0"), which
> in this case isn't true, and as it searches through the children of
> "ethernet-switch@0", it finds no MDIO bus to probe.
>
> Cc: Lee Jones <lee@kernel.org>
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
> ---
> drivers/mfd/mfd-core.c | 11 +++++++++--
> include/linux/mfd/core.h | 7 +++++++
> 2 files changed, 16 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
> index 7d14a1e7631e..e0b7f93a2654 100644
> --- a/drivers/mfd/mfd-core.c
> +++ b/drivers/mfd/mfd-core.c
> @@ -181,8 +181,14 @@ static int mfd_add_device(struct device *parent, int id,
> if (ret < 0)
> goto fail_res;
>
> - if (IS_ENABLED(CONFIG_OF) && parent->of_node && cell->of_compatible) {
> - for_each_child_of_node(parent->of_node, np) {
> + if (IS_ENABLED(CONFIG_OF)) {
> + const struct device_node *parent_of_node;
> +
> + parent_of_node = cell->parent_of_node ?: parent->of_node;
> + if (!parent_of_node || !cell->of_compatible)
> + goto skip_of;
> +
> + for_each_child_of_node(parent_of_node, np) {
> if (of_device_is_compatible(np, cell->of_compatible)) {
> /* Skip 'disabled' devices */
> if (!of_device_is_available(np)) {
> @@ -213,6 +219,7 @@ static int mfd_add_device(struct device *parent, int id,
> cell->name, platform_id);
> }
>
> +skip_of:
> mfd_acpi_add_device(cell, pdev);
>
> if (cell->pdata_size) {
> diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h
> index faeea7abd688..2e94ea376125 100644
> --- a/include/linux/mfd/core.h
> +++ b/include/linux/mfd/core.h
> @@ -81,6 +81,13 @@ struct mfd_cell {
> /* Software node for the device. */
> const struct software_node *swnode;
>
> + /*
> + * Parent OF node of the device, if different from the OF node
> + * of the MFD parent (e.g. there is at least one more hierarchical
> + * level between them)
> + */
> + const struct device_node *parent_of_node;
> +
> /*
> * Device Tree compatible string
> * See: Documentation/devicetree/usage-model.rst Chapter 2.2 for details
> --
> 2.34.1
>
--
Lee Jones [李琼斯]
On Thu, Nov 20, 2025 at 02:41:36PM +0000, Lee Jones wrote:
> On Tue, 18 Nov 2025, Vladimir Oltean wrote:
>
> > I would like the "nxp,sja1110a" driver, in the configuration below, to
> > be able to probe the drivers for "nxp,sja1110-base-t1-mdio" and for
> > "nxp,sja1110-base-tx-mdio" via mfd_add_devices():
> >
> > ethernet-switch@0 {
> > compatible = "nxp,sja1110a";
> >
> > mdios {
> > mdio@0 {
> > compatible = "nxp,sja1110-base-t1-mdio";
> > };
> >
> > mdio@1 {
> > compatible = "nxp,sja1110-base-tx-mdio";
> > };
> > };
> > };
>
> This device is not an MFD.
>
> Please find a different way to instantiate these network drivers.
Ok.. but what is an MFD? I'm seriously interested in a definition.
One data point: the VSC7512 (driver in drivers/mfd/ocelot-spi.c,
bindings in Documentation/devicetree/bindings/mfd/mscc,ocelot.yaml) is
almost the same class of hardware (except the embedded Cortex-M7 in
SJA1110 can't run Linux, and the CPU in VSC7512 can). It instantiates
MDIO bus children, like this patch proposes too, except it works with a
different device tree hierarchy which I need to adapt to, without breaking.
On Thu, 20 Nov 2025, Vladimir Oltean wrote:
> On Thu, Nov 20, 2025 at 02:41:36PM +0000, Lee Jones wrote:
> > On Tue, 18 Nov 2025, Vladimir Oltean wrote:
> >
> > > I would like the "nxp,sja1110a" driver, in the configuration below, to
> > > be able to probe the drivers for "nxp,sja1110-base-t1-mdio" and for
> > > "nxp,sja1110-base-tx-mdio" via mfd_add_devices():
> > >
> > > ethernet-switch@0 {
> > > compatible = "nxp,sja1110a";
> > >
> > > mdios {
> > > mdio@0 {
> > > compatible = "nxp,sja1110-base-t1-mdio";
> > > };
> > >
> > > mdio@1 {
> > > compatible = "nxp,sja1110-base-tx-mdio";
> > > };
> > > };
> > > };
> >
> > This device is not an MFD.
> >
> > Please find a different way to instantiate these network drivers.
>
> Ok.. but what is an MFD? I'm seriously interested in a definition.
>
> One data point: the VSC7512 (driver in drivers/mfd/ocelot-spi.c,
> bindings in Documentation/devicetree/bindings/mfd/mscc,ocelot.yaml) is
> almost the same class of hardware (except the embedded Cortex-M7 in
> SJA1110 can't run Linux, and the CPU in VSC7512 can). It instantiates
> MDIO bus children, like this patch proposes too, except it works with a
> different device tree hierarchy which I need to adapt to, without breaking.
The devices should be different types i.e. be located in different
subsystems. If you're simply instantiating Watchdog timers, the code
should live solely in drivers/watchdog. If the devices all pertain to
Networking, the code should live in the Networking subsystem, etc.
MFD is Linuxisum, simply used to split devices up such that each
component can be located it their own applicable subsystem and be
reviewed and maintained by the subject matter experts of those domains.
TL;DR: if your device only deals with Networking, that's where it should
live. And from there, it should handle its own device registration and
instantiation without reaching into other, non-related subsystems.
--
Lee Jones [李琼斯]
On Fri, Nov 21, 2025 at 12:06:46PM +0000, Lee Jones wrote: > MFD is Linuxisum, simply used to split devices up such that each > component can be located it their own applicable subsystem and be > reviewed and maintained by the subject matter experts of those domains. Perfect, so the SJA1110 fits the MFD bill perfectly. I'm getting the impression that the more I write to explain, the fewer chances I have for you to read. I'll try to keep things as concise as I can, but please remember that: - We've had the exact same discussions with Colin Foster's VSC7512 work, which you ended up accepting - This email sent to you in 2022 and again in the other reply on patch 8: https://lore.kernel.org/lkml/20221222134844.lbzyx5hz7z5n763n@skbuf/ already explains what is the kind of hardware I'm dealing with > TL;DR: if your device only deals with Networking, that's where it should > live. And from there, it should handle its own device registration and > instantiation without reaching into other, non-related subsystems. Ok, you make a vague reference which I think I understand the point of. I need to merge the discussion with the one from patch 8: https://lore.kernel.org/netdev/20251121120037.GA1117685@google.com/ where you say: | Another more recent avenue you may explore is the Auxiliary Bus. Excerpt from documentation here: https://docs.kernel.org/driver-api/auxiliary_bus.html When Should the Auxiliary Bus Be Used (...) The emphasis here is on a common generic interface that keeps subsystem customization out of the bus infrastructure. (...) A key requirement for utilizing the auxiliary bus is that there is no dependency on a physical bus, device, register accesses or regmap support. These individual devices split from the core cannot live on the platform bus as they are not physical devices that are controlled by DT/ACPI. The same argument applies for not using MFD in this scenario as MFD relies on individual function devices being physical devices. The thesis I need to defend is that the SJA1110 usage is 100% fit for MFD and 0% auxiliary bus. In order to explain it I have to give a bit of history on DSA. DSA is a Linuxism for managing Ethernet switches. Key thing is they are a hardware IP with registers to configure them. There are many ways to integrate an Ethernet switch hardware IP in a chip that you sell. You can (a) sell the IP itself for SoC vendors to put in their address space and access using MMIO, or you can (b) sell them an entire chip with the switch IP in it, that they access over a bus like PCIe, SPI, I2C, MDIO, whatever, and integrate with their existing Linux SoC. DSA has started from a place where it didn't really understand that its core domain of expertise was the Ethernet switching IP itself. The first devices it supported were all of the (b) kind, discrete chips on buses. Thus, many drivers were written where DSA takes charge of the struct spi_device, mdio_device, i2c_client etc. These early drivers are simplistic, they configure the switch to pass traffic, and the PHYs through the internal MDIO bus to establish a link, and voila! They pass traffic, they're good to go. Then you start to want to develop these further. You want to avoid polling PHYs for link status every second.. well, you find there's an interrupt controller in that chip too, that you should be using with irqchip. You want to read the chip's temperature to prevent it from overheating - you find temperature sensors too, for which you register with hwmon. You find reset blocks, clock generation blocks, power management blocks, GPIO controllers, what have you. See, the more you look at the datasheet, the more you start to notice an entire universe of hardware IPs, and then.. you notice a microcontroller! Those hardware IPs are all also memory-mapped in the address space of that microcontroller, and when you from Linux are accessing them, you're just going through a SPI-to-AHB bridge. Things become really shitty when the DSA chip that you want to drive from drivers/net/dsa has a full-blown microprocessor capable of running Linux instead of that microcontroller! Then you have to support driving the same switch from the small Linux, using MMIO, or from the big Linux, over SPI. Out of a lack of expressivity that we as engineers have, we call both the SoC at large "a switch", and the switching IP "a switch". Hell, we even call the rack-mounted pizza box computer with many ports "a switch", no wonder nobody understands anything! We just name things after the most important thing that's in them. So unwind 100 steps from the rabbit hole and ask: what does DSA concern itself with? Ideally, the answer is "the Ethernet switch IP". This is always mapped in somebody's address space from address X to Y. Practically, legacy makes it that DSA concerns itself with the entire address space of SPI devices, MDIO devices, I2C devices etc. If you imagine a microprocessor in these discrete chips (which is architecturally almost always possible), the device tree of that would only describe a single region with the Ethernet switching IP, and Linux would probe a platform device for that. The rest is.. other stuff (of various degrees of functional relatedness, but nonetheless, other stuff) with *other* platform devices. So, DSA is in a process of trying to define a conversion model that is coherent, compatible with the past, minimal in its description, applicable to other devices, and not a pain in the butt. Fact of the matter is, we will always clash with the MFD maintainer in this process, and it simply doesn't scale for us to keep repeating the same stuff over and over. It is just too much friction. We went through this once, with Colin Foster who added the Microchip VSC7512 as MFD through your tree, and that marked the first time when a DSA driver over a SPI device concerned itself with just the switching IP, using MFD as the abstraction layer. The NXP SJA1110 is just another step in that journey, but this one is harder because it has legacy device tree bindings to maintain. However, if we are to accept that Colin Foster's work was not an architectural mistake, then the SJA1110 is not the end of the road either, and you have to be prepared for more devices to come and do the same thing. So practically speaking, the fact that DSA has these particular needs is just a fact. Treat the above description as a "global prompt", if you will :) So why not the auxiliary bus? That creates auxiliary_device structures, which are fake things that some core device wants to keep out to make things leaner. But what we want is a platform_device, because that is the common denominator between what kind of drivers the "small Linux" and the "big Linux" would use for the same hardware IPs. MFD gives us exactly that, and regmap provides the abstraction between MMIO and SPI. ================================================================ The above was the "global prompt" that you need to have in your context, now let's return to the patch at hand. SJA1110 is *not* capable of running Linux inside. This allows us to get away with partial conversions, where the DSA driver still remains in charge of the entire SPI device, but delegates the other stuff to MFD. The existing bindings cannot be broken. Hindsight is 20/20, but whatever stupid decisions I made in the past with this "mdios" container node are there to stay.
Sorry for the delay. Just getting around to some task items en-route back from Plumbers. > On Fri, Nov 21, 2025 at 12:06:46PM +0000, Lee Jones wrote: > > MFD is Linuxisum, simply used to split devices up such that each > > component can be located it their own applicable subsystem and be > > reviewed and maintained by the subject matter experts of those domains. > > Perfect, so the SJA1110 fits the MFD bill perfectly. > > I'm getting the impression that the more I write to explain, the fewer > chances I have for you to read. I'll try to keep things as concise as I > can, but please remember that: > - We've had the exact same discussions with Colin Foster's VSC7512 > work, which you ended up accepting > - This email sent to you in 2022 and again in the other reply on patch 8: > https://lore.kernel.org/lkml/20221222134844.lbzyx5hz7z5n763n@skbuf/ > already explains what is the kind of hardware I'm dealing with > > > TL;DR: if your device only deals with Networking, that's where it should > > live. And from there, it should handle its own device registration and > > instantiation without reaching into other, non-related subsystems. > > Ok, you make a vague reference which I think I understand the point of. > > I need to merge the discussion with the one from patch 8: > https://lore.kernel.org/netdev/20251121120037.GA1117685@google.com/ > where you say: > > | Another more recent avenue you may explore is the Auxiliary Bus. > > Excerpt from documentation here: > https://docs.kernel.org/driver-api/auxiliary_bus.html > > When Should the Auxiliary Bus Be Used > > (...) > The emphasis here is on a common generic interface that keeps subsystem > customization out of the bus infrastructure. > (...) > A key requirement for utilizing the auxiliary bus is that there is no > dependency on a physical bus, device, register accesses or regmap > support. These individual devices split from the core cannot live on the > platform bus as they are not physical devices that are controlled by > DT/ACPI. The same argument applies for not using MFD in this scenario as > MFD relies on individual function devices being physical devices. > > The thesis I need to defend is that the SJA1110 usage is 100% fit for > MFD and 0% auxiliary bus. In order to explain it I have to give a bit of > history on DSA. > > DSA is a Linuxism for managing Ethernet switches. Key thing is they are > a hardware IP with registers to configure them. There are many ways > to integrate an Ethernet switch hardware IP in a chip that you sell. > You can (a) sell the IP itself for SoC vendors to put in their address > space and access using MMIO, or you can (b) sell them an entire chip > with the switch IP in it, that they access over a bus like PCIe, SPI, > I2C, MDIO, whatever, and integrate with their existing Linux SoC. > > DSA has started from a place where it didn't really understand that its > core domain of expertise was the Ethernet switching IP itself. The first > devices it supported were all of the (b) kind, discrete chips on buses. > Thus, many drivers were written where DSA takes charge of the struct > spi_device, mdio_device, i2c_client etc. > > These early drivers are simplistic, they configure the switch to pass > traffic, and the PHYs through the internal MDIO bus to establish a link, > and voila! They pass traffic, they're good to go. > > Then you start to want to develop these further. You want to avoid > polling PHYs for link status every second.. well, you find there's an > interrupt controller in that chip too, that you should be using with > irqchip. You want to read the chip's temperature to prevent it from > overheating - you find temperature sensors too, for which you register > with hwmon. You find reset blocks, clock generation blocks, power > management blocks, GPIO controllers, what have you. > > See, the more you look at the datasheet, the more you start to notice > an entire universe of hardware IPs, and then.. you notice a microcontroller! > Those hardware IPs are all also memory-mapped in the address space of > that microcontroller, and when you from Linux are accessing them, you're > just going through a SPI-to-AHB bridge. > > Things become really shitty when the DSA chip that you want to drive > from drivers/net/dsa has a full-blown microprocessor capable of running > Linux instead of that microcontroller! Then you have to support driving > the same switch from the small Linux, using MMIO, or from the big Linux, > over SPI. > > Out of a lack of expressivity that we as engineers have, we call both > the SoC at large "a switch", and the switching IP "a switch". Hell, > we even call the rack-mounted pizza box computer with many ports "a switch", > no wonder nobody understands anything! We just name things after the > most important thing that's in them. > > So unwind 100 steps from the rabbit hole and ask: what does DSA concern > itself with? > > Ideally, the answer is "the Ethernet switch IP". This is always mapped > in somebody's address space from address X to Y. > > Practically, legacy makes it that DSA concerns itself with the entire > address space of SPI devices, MDIO devices, I2C devices etc. If you > imagine a microprocessor in these discrete chips (which is architecturally > almost always possible), the device tree of that would only describe a > single region with the Ethernet switching IP, and Linux would probe a > platform device for that. The rest is.. other stuff (of various degrees > of functional relatedness, but nonetheless, other stuff) with *other* > platform devices. > > So, DSA is in a process of trying to define a conversion model that is > coherent, compatible with the past, minimal in its description, > applicable to other devices, and not a pain in the butt. > > Fact of the matter is, we will always clash with the MFD maintainer in > this process, and it simply doesn't scale for us to keep repeating the > same stuff over and over. It is just too much friction. We went through > this once, with Colin Foster who added the Microchip VSC7512 as MFD > through your tree, and that marked the first time when a DSA driver over > a SPI device concerned itself with just the switching IP, using MFD as > the abstraction layer. > > The NXP SJA1110 is just another step in that journey, but this one is > harder because it has legacy device tree bindings to maintain. However, > if we are to accept that Colin Foster's work was not an architectural > mistake, then the SJA1110 is not the end of the road either, and you > have to be prepared for more devices to come and do the same thing. > > So practically speaking, the fact that DSA has these particular needs > is just a fact. Treat the above description as a "global prompt", if you > will :) > > So why not the auxiliary bus? That creates auxiliary_device structures, > which are fake things that some core device wants to keep out to make > things leaner. But what we want is a platform_device, because that is > the common denominator between what kind of drivers the "small Linux" > and the "big Linux" would use for the same hardware IPs. MFD gives us > exactly that, and regmap provides the abstraction between MMIO and SPI. > > ================================================================ > > The above was the "global prompt" that you need to have in your context, > now let's return to the patch at hand. > > SJA1110 is *not* capable of running Linux inside. This allows us to get > away with partial conversions, where the DSA driver still remains in > charge of the entire SPI device, but delegates the other stuff to MFD. > > The existing bindings cannot be broken. Hindsight is 20/20, but whatever > stupid decisions I made in the past with this "mdios" container node are > there to stay. Thanks for drafting all of this. It's not an ideal level of verboseness for a busy maintainer with 50+ of reviews to do, but I appreciate your depth of knowledge and the eloquence of the writing. There does appear to be at least some level of misunderstanding between us. I'm not for one moment suggesting that a switch can't be an MFD. If it contains probe-able components that need to be split-up across multiple different subsystems, then by all means, move the core driver into drivers/mfd/ and register child devices 'till your heart's content. What I am saying, however, is that from what I can see in front of me, there doesn't appear to be any evidence that this device belongs there. Unless there's something I'm missing, it looks awfully like you're simply trying to register a couple of platform deices devices and you've chosen to use the MFD API as a convenient way to do so. That is not what MFD is for. Side note: The implementation is also janky. > Fact of the matter is, we will always clash with the MFD maintainer in > this process, and it simply doesn't scale for us to keep repeating the > same stuff over and over. It is just too much friction. We went through > this once, with Colin Foster who added the Microchip VSC7512 as MFD > through your tree, and that marked the first time when a DSA driver over > a SPI device concerned itself with just the switching IP, using MFD as > the abstraction layer. I don't recall those discussions from 3 years ago, but the Ocelot platform, whatever it may be, seems to have quite a lot more cross-subsystem device support requirements going on than I see here: drivers/i2c/busses/i2c-designware-platdrv.c drivers/irqchip/irq-mscc-ocelot.c drivers/mfd/ocelot-* drivers/net/dsa/ocelot/* drivers/net/ethernet/mscc/ocelot* drivers/net/mdio/mdio-mscc-miim.c drivers/phy/mscc/phy-ocelot-serdes.c drivers/pinctrl/pinctrl-microchip-sgpio.c drivers/pinctrl/pinctrl-ocelot.c drivers/power/reset/ocelot-reset.c drivers/spi/spi-dw-mmio.c net/dsa/tag_ocelot_8021q.c > - We've had the exact same discussions with Colin Foster's VSC7512 > work, which you ended up accepting Quick update: After doing a little searching for Colin's original patch-set, I've managed to find as far back as v5 (v16 was merged), which I believe was the first version that proposed using MFD. There were lots of review comments and an insistence to add more than one device (rather than adding them subsequently) to make it a true MFD, however, I don't see any suggestion that MFD wasn't the right place for it. > Then you start to want to develop these further. You want to avoid > polling PHYs for link status every second.. well, you find there's an > interrupt controller in that chip too, that you should be using with > irqchip. You want to read the chip's temperature to prevent it from > overheating - you find temperature sensors too, for which you register > with hwmon. You find reset blocks, clock generation blocks, power > management blocks, GPIO controllers, what have you. Absolutely! MFD would be perfect for that. My point is, you don't seem to have have any of that here. -- Lee Jones [李琼斯]
Hello Lee, On Mon, Dec 15, 2025 at 03:50:28PM +0000, Lee Jones wrote: > Thanks for drafting all of this. It's not an ideal level of verboseness > for a busy maintainer with 50+ of reviews to do, but I appreciate your > depth of knowledge and the eloquence of the writing. Thanks for coming back and I hope your time at LPC was spent usefully. I will try to reorder your messages to group the replies in the way that is most efficient. > Side note: The implementation is also janky. Yes, this is why it's up for review, so I can learn why it's janky and fix it. > There does appear to be at least some level of misunderstanding between > us. I'm not for one moment suggesting that a switch can't be an MFD. If > it contains probe-able components that need to be split-up across > multiple different subsystems, then by all means, move the core driver > into drivers/mfd/ and register child devices 'till your heart's content. Are you still speaking generically here, or have you actually looked at any "nxp,sja1105q" or "nxp,sja1110a" device trees to see what it would mean for these compatible strings to be probed by a driver in drivers/mfd? What OF node would remain for the DSA switch (child) device driver? The same? Or are you suggesting that the entire drivers/net/dsa/sja1105/ would move to drivers/mfd/? Or? > What I am saying, however, is that from what I can see in front of me, > there doesn't appear to be any evidence that this device belongs there. > > Unless there's something I'm missing, it looks awfully like you're > simply trying to register a couple of platform deices devices and you've > chosen to use the MFD API as a convenient way to do so. That is not > what MFD is for. I may be just uneducated here, but I'm genuinely perplexed. Isn't the MFD API a convenient way to instantiate resources of a device into platform sub-devices for _everyone_ who uses it? Is it more than that? I don't know how to defend this. > > Fact of the matter is, we will always clash with the MFD maintainer in > > this process, and it simply doesn't scale for us to keep repeating the > > same stuff over and over. It is just too much friction. We went through > > this once, with Colin Foster who added the Microchip VSC7512 as MFD > > through your tree, and that marked the first time when a DSA driver over > > a SPI device concerned itself with just the switching IP, using MFD as > > the abstraction layer. > > I don't recall those discussions from 3 years ago, but the Ocelot > platform, whatever it may be, seems to have quite a lot more > cross-subsystem device support requirements going on than I see here: > > drivers/i2c/busses/i2c-designware-platdrv.c > drivers/irqchip/irq-mscc-ocelot.c > drivers/mfd/ocelot-* > drivers/net/dsa/ocelot/* > drivers/net/ethernet/mscc/ocelot* > drivers/net/mdio/mdio-mscc-miim.c > drivers/phy/mscc/phy-ocelot-serdes.c > drivers/pinctrl/pinctrl-microchip-sgpio.c > drivers/pinctrl/pinctrl-ocelot.c > drivers/power/reset/ocelot-reset.c > drivers/spi/spi-dw-mmio.c > net/dsa/tag_ocelot_8021q.c This is a natural effect of Ocelot being "whatever it may be". It is a family of networking SoCs, of which VSC7514 has a MIPS CPU and Linux port, where the above drivers are used. The VSC7512 is then a simplified variant with the MIPS CPU removed, and the internal components controlled externally over SPI. Hence MFD to reuse the same drivers as Linux on MIPS (using MMIO) did. This is all that matters, not the quantity. > > - We've had the exact same discussions with Colin Foster's VSC7512 > > work, which you ended up accepting > > Quick update: After doing a little searching for Colin's original > patch-set, I've managed to find as far back as v5 (v16 was merged), > which I believe was the first version that proposed using MFD. There > were lots of review comments and an insistence to add more than one > device (rather than adding them subsequently) to make it a true MFD, > however, I don't see any suggestion that MFD wasn't the right place for > it. > > > Then you start to want to develop these further. You want to avoid > > polling PHYs for link status every second.. well, you find there's an > > interrupt controller in that chip too, that you should be using with > > irqchip. You want to read the chip's temperature to prevent it from > > overheating - you find temperature sensors too, for which you register > > with hwmon. You find reset blocks, clock generation blocks, power > > management blocks, GPIO controllers, what have you. > > Absolutely! MFD would be perfect for that. > > My point is, you don't seem to have have any of that here. What do you want to see exactly which is not here? I have converted three classes of sub-devices on the NXP SJA1110 to MFD children in this patch set. Two MDIO buses and an Ethernet PCS for SGMII. In the SJA1110 memory map, the important resources look something like this: Name Description Start End SWITCH Ethernet Switch Subsystem 0x000000 0x3ffffc 100BASE-T1 Internal MDIO bus for 100BASE-T1 PHY (port 5 - 10) 0x704000 0x704ffc SGMII1 SGMII Port 1 0x705000 0x705ffc SGMII2 SGMII Port 2 0x706000 0x706ffc SGMII3 SGMII Port 3 0x707000 0x707ffc SGMII4 SGMII Port 4 0x708000 0x708ffc 100BASE-TX Internal MDIO bus for 100BASE-TX PHY 0x709000 0x709ffc ACU Auxiliary Control Unit 0x711000 0x711ffc GPIO General Purpose Input/Output 0x712000 0x712ffc I need to remind you that my purpose here is not to add drivers in breadth for all SJA1110 sub-devices now. But rather, a concrete use case (SGMII polarity inversion) has appeared which requires the SGMII1..SGMII4 blocks to appear in the device tree (so far, the SJA1110 driver has happily programmed these blocks based on hardcoded SPI addresses in the driver, and there hasn't existed a reason to describe them in the DT). The SGMII blocks are highly reusable IPs licensed from Synopsys, and Linux already has DT bindings and a corresponding platform driver for the case where their registers are viewed using MMIO. So my proposal in patch 14/15 is to create the following DT sub-nodes of the DSA switch: - regs/ethernet-pcs@705000 for SGMII1 - regs/ethernet-pcs@706000 for SGMII2 - regs/ethernet-pcs@707000 for SGMII3 - regs/ethernet-pcs@708000 for SGMII4 and to use MFD so that the xpcs-plat driver currently used for the MMIO case "just works" for the "register view over SPI" case, and the SPI DT node inherits the same bindings. In this sense, it is exactly the same problem and solution as Colin Foster's ocelot set, at a smaller scale (just one sub-device of this switch already had an established MMIO driver). https://lore.kernel.org/netdev/20251118190530.580267-15-vladimir.oltean@nxp.com/ Furthermore, I also finalized the split of region handling that started with the aforementioned SGMII blocks, by making the DSA driver stop accessing the 100BASE-T1 and 100BASE-TX regions directly, and use MFD to probe separate drivers for these resources. I did not _have_ to do this for 100BASE-T1 and 100BASE-TX, but the intention behind doing it was to solidify the argument that this device has multiple regions for which the MFD model is suitable, rather than impair it. In the upstream DT bindings of the switch, the 100BASE-T1 region has a corresponding mdios/mdio@0 child node, and the resource is hardcoded in the driver. Similarly, the 100BASE-TX region is described as the mdios/mdio@1 child. This is what I need this patch (07/15) for. The intention is for all future sub-devices of the switch to live under the "regs" sub-node, with the exception of "mdios/mdio@0" and "mdios/mdio@1" which are already established somewhere else via a stable ABI. This makes the SJA1110 a hybrid DSA+MFD driver, due to the impossibility of getting rid of current DT bindings (this, plus the fact that I don't necessarily see a problem with them). In my opinion I do not need to add handling for any other sub-device, for the support to be more "cross-system" like for Ocelot. What is here is enough for you to decide if this is adequate for MFD or not. The driver for SJA1110 needs a path forward from point A (where it handles some resources internally which are outside the SWITCH region) to point B (where those resources are handled by their correct reusable drivers with specific DT bindings which we need). At the very least, I expect you to clarify what are the problems you perceive in MFD being part of this transition. I'd rather not speculate, and your previous response is not sufficiently applied to the problem at hand.
> > Side note: The implementation is also janky. > > Yes, this is why it's up for review, so I can learn why it's janky and > fix it. I'd be happy to discuss this in great detail if we finally conclude that this device is suitable for MFD. Spoiler alert: Unless you add/convert more child devices that are outside of net/ and drivers/net AND move the core MFD usage to drivers/mfd/, then we can't conclude that. > > There does appear to be at least some level of misunderstanding between > > us. I'm not for one moment suggesting that a switch can't be an MFD. If > > it contains probe-able components that need to be split-up across > > multiple different subsystems, then by all means, move the core driver > > into drivers/mfd/ and register child devices 'till your heart's content. > > Are you still speaking generically here, or have you actually looked at > any "nxp,sja1105q" or "nxp,sja1110a" device trees to see what it would > mean for these compatible strings to be probed by a driver in drivers/mfd? It's not my role to go digging into existing implementations and previous submissions to prove whether a particular submission is suitable for inclusion into MFD. Please put in front of me, in a concise way (please), why you think this is fit for inclusion. I've explained what is usually required, but I'll (over-)simplify again for clarity: - The mfd_* API call-sites must only exist in drivers/mfd/ - Consumers usually spit out non-system specific logic into a 'core' - MFDs need to have more than one child - This is where the 'Multi' comes in - Children should straddle different sub-systems - drivers/net is not enough [0] - If all of your sub-devices are in 'net' use the platform_* API - <other stipulations less relevant to this stipulation> ... There will always be exceptions, but previous mistakes are not good justifications for future ones. [0] .../bindings/net/dsa/nxp,sja1105.yaml | 28 + .../bindings/net/pcs/snps,dw-xpcs.yaml | 8 + MAINTAINERS | 2 + drivers/mfd/mfd-core.c | 11 +- drivers/net/dsa/sja1105/Kconfig | 2 + drivers/net/dsa/sja1105/Makefile | 2 +- drivers/net/dsa/sja1105/sja1105.h | 42 +- drivers/net/dsa/sja1105/sja1105_main.c | 169 +++--- drivers/net/dsa/sja1105/sja1105_mdio.c | 507 ------------------ drivers/net/dsa/sja1105/sja1105_mfd.c | 293 ++++++++++ drivers/net/dsa/sja1105/sja1105_mfd.h | 11 + drivers/net/dsa/sja1105/sja1105_spi.c | 113 +++- drivers/net/mdio/Kconfig | 21 +- drivers/net/mdio/Makefile | 2 + drivers/net/mdio/mdio-regmap-simple.c | 77 +++ drivers/net/mdio/mdio-regmap.c | 7 +- drivers/net/mdio/mdio-sja1110-cbt1.c | 173 ++++++ drivers/net/pcs/pcs-xpcs-plat.c | 146 +++-- drivers/net/pcs/pcs-xpcs.c | 12 + drivers/net/phy/phylink.c | 75 ++- include/linux/mdio/mdio-regmap.h | 2 + include/linux/mfd/core.h | 7 + include/linux/pcs/pcs-xpcs.h | 1 + include/linux/phylink.h | 5 + 24 files changed, 1033 insertions(+), 683 deletions(-) delete mode 100644 drivers/net/dsa/sja1105/sja1105_mdio.c create mode 100644 drivers/net/dsa/sja1105/sja1105_mfd.c create mode 100644 drivers/net/dsa/sja1105/sja1105_mfd.h create mode 100644 drivers/net/mdio/mdio-regmap-simple.c create mode 100644 drivers/net/mdio/mdio-sja1110-cbt1.c > What OF node would remain for the DSA switch (child) device driver? The same? > Or are you suggesting that the entire drivers/net/dsa/sja1105/ would > move to drivers/mfd/? Or? See bullet 1.1 above. [...] > > I don't recall those discussions from 3 years ago, but the Ocelot > > platform, whatever it may be, seems to have quite a lot more > > cross-subsystem device support requirements going on than I see here: > > > > drivers/i2c/busses/i2c-designware-platdrv.c > > drivers/irqchip/irq-mscc-ocelot.c > > drivers/mfd/ocelot-* > > drivers/net/dsa/ocelot/* > > drivers/net/ethernet/mscc/ocelot* > > drivers/net/mdio/mdio-mscc-miim.c > > drivers/phy/mscc/phy-ocelot-serdes.c > > drivers/pinctrl/pinctrl-microchip-sgpio.c > > drivers/pinctrl/pinctrl-ocelot.c > > drivers/power/reset/ocelot-reset.c > > drivers/spi/spi-dw-mmio.c > > net/dsa/tag_ocelot_8021q.c > > This is a natural effect of Ocelot being "whatever it may be". It is a > family of networking SoCs, of which VSC7514 has a MIPS CPU and Linux > port, where the above drivers are used. The VSC7512 is then a simplified > variant with the MIPS CPU removed, and the internal components controlled > externally over SPI. Hence MFD to reuse the same drivers as Linux on > MIPS (using MMIO) did. This is all that matters, not the quantity. From what I can see, Ocelot ticks all of the boxes for MFD API usage, whereas this submission does not. The fact that the overarching device provides a similar function is neither here nor there. These are the results from my searches of your device: git grep -i SJA1110 | grep -v 'net\|arch\|include' <no results> [...] > > My point is, you don't seem to have have any of that here. > > What do you want to see exactly which is not here? > > I have converted three classes of sub-devices on the NXP SJA1110 to MFD > children in this patch set. Two MDIO buses and an Ethernet PCS for SGMII. > > In the SJA1110 memory map, the important resources look something like this: > > Name Description Start End > SWITCH Ethernet Switch Subsystem 0x000000 0x3ffffc > 100BASE-T1 Internal MDIO bus for 100BASE-T1 PHY (port 5 - 10) 0x704000 0x704ffc > SGMII1 SGMII Port 1 0x705000 0x705ffc > SGMII2 SGMII Port 2 0x706000 0x706ffc > SGMII3 SGMII Port 3 0x707000 0x707ffc > SGMII4 SGMII Port 4 0x708000 0x708ffc > 100BASE-TX Internal MDIO bus for 100BASE-TX PHY 0x709000 0x709ffc All in drivers/net. > ACU Auxiliary Control Unit 0x711000 0x711ffc > GPIO General Purpose Input/Output 0x712000 0x712ffc Where are these drivers? > I need to remind you that my purpose here is not to add drivers in > breadth for all SJA1110 sub-devices now. You'll see from my discussions with Colin, sub-drivers (if they are to be used for MFD justification (point 3 above), then they must be added as part of the first submission. Perhaps this isn't an MFD, "yet"? [...] > The SGMII blocks are highly reusable IPs licensed from Synopsys, and > Linux already has DT bindings and a corresponding platform driver for > the case where their registers are viewed using MMIO. This is a good reason for dividing them up into subordinate platform devices. However, it is not a good use-case of MFD. In it's current guise, your best bet is to use the platform_* API directly. This is a well trodden path and it not challenging: % git grep platform_device_add -- arch drivers sound | wc -l 398 [...] > In my opinion I do not need to add handling for any other sub-device, > for the support to be more "cross-system" like for Ocelot. What is here > is enough for you to decide if this is adequate for MFD or not. Currently ... it's not. [...] Hopefully that helps to clarify my expectations a little. TL;DR, this looks like a good candidate for direct platform_* usage. -- Lee Jones [李琼斯]
> > Name Description Start End > > SWITCH Ethernet Switch Subsystem 0x000000 0x3ffffc > > 100BASE-T1 Internal MDIO bus for 100BASE-T1 PHY (port 5 - 10) 0x704000 0x704ffc > > SGMII1 SGMII Port 1 0x705000 0x705ffc > > SGMII2 SGMII Port 2 0x706000 0x706ffc > > SGMII3 SGMII Port 3 0x707000 0x707ffc > > SGMII4 SGMII Port 4 0x708000 0x708ffc > > 100BASE-TX Internal MDIO bus for 100BASE-TX PHY 0x709000 0x709ffc > > All in drivers/net. I've not been following this conversation too much, but i would like to point out that what you find in drivers/net is not a uniform set of drivers, but a collection of different driver types. SWITCH might belong on drivers/net/dsa 100BASE-T1 might belong on drivers/net/mdio SGMIIX might belong in drivers/net/pcs 100BASE-TX might belong in drivers/net/mdio I also expect those T1 and TX PHYs have drivers in drivers/net/phy, but they are not memory mapped, so not on your list. Each driver can probe independently, registering with different parts of the net core. And then the switch driver will link all the parts together using phandles. Saying that all the sub drivers are in drivers/net seems an odd argument it is not an MFD. Andrew
On Wed, 17 Dec 2025, Andrew Lunn wrote: > > > Name Description Start End > > > SWITCH Ethernet Switch Subsystem 0x000000 0x3ffffc > > > 100BASE-T1 Internal MDIO bus for 100BASE-T1 PHY (port 5 - 10) 0x704000 0x704ffc > > > SGMII1 SGMII Port 1 0x705000 0x705ffc > > > SGMII2 SGMII Port 2 0x706000 0x706ffc > > > SGMII3 SGMII Port 3 0x707000 0x707ffc > > > SGMII4 SGMII Port 4 0x708000 0x708ffc > > > 100BASE-TX Internal MDIO bus for 100BASE-TX PHY 0x709000 0x709ffc > > > > All in drivers/net. > > I've not been following this conversation too much, but i would like > to point out that what you find in drivers/net is not a uniform set of > drivers, but a collection of different driver types. > > SWITCH might belong on drivers/net/dsa > 100BASE-T1 might belong on drivers/net/mdio > SGMIIX might belong in drivers/net/pcs > 100BASE-TX might belong in drivers/net/mdio > > I also expect those T1 and TX PHYs have drivers in drivers/net/phy, > but they are not memory mapped, so not on your list. > > Each driver can probe independently, registering with different parts > of the net core. And then the switch driver will link all the parts > together using phandles. > > Saying that all the sub drivers are in drivers/net seems an odd > argument it is not an MFD. Okay, I'm convinced. Thanks for the additional context. -- Lee Jones [李琼斯]
On Tue, Dec 16, 2025 at 09:18:31AM +0000, Lee Jones wrote: > Unless you add/convert more child devices that are outside of net/ and > drivers/net AND move the core MFD usage to drivers/mfd/, then we can't > conclude that [ this device is suitable for MFD ]. To me, the argument that child devices can't all be under drivers/net/ is superficial. An mii_bus is very different in purpose from a phylink_pcs and from a net_device, yet all 3 live in drivers/net/. Furthermore, I am looking at schemas such as /devicetree/bindings/mfd/adi,max77541.yaml: "MAX77540 is a Power Management IC with 2 buck regulators." and I don't understand how it possibly passed this criterion. It is one chip with two devices of the same kind, and nothing else. If moving the core MFD usage to drivers/mfd/ is another hard requirement, this is also attacking form rather than substance. You as the MFD maintainer can make an appeal to authority and NACK aesthetics you don't like, but I just want everyone to be on the same page about this. > > > There does appear to be at least some level of misunderstanding between > > > us. I'm not for one moment suggesting that a switch can't be an MFD. If > > > it contains probe-able components that need to be split-up across > > > multiple different subsystems, then by all means, move the core driver > > > into drivers/mfd/ and register child devices 'till your heart's content. > > > > Are you still speaking generically here, or have you actually looked at > > any "nxp,sja1105q" or "nxp,sja1110a" device trees to see what it would > > mean for these compatible strings to be probed by a driver in drivers/mfd? > > It's not my role to go digging into existing implementations and > previous submissions to prove whether a particular submission is > suitable for inclusion into MFD. > > Please put in front of me, in a concise way (please), why you think this > is fit for inclusion. No new information, I think the devices are fit for MFD because of their memory map which was shown in the previous reply. > I've explained what is usually required, but I'll (over-)simplify > again for clarity: > > - The mfd_* API call-sites must only exist in drivers/mfd/ > - Consumers usually spit out non-system specific logic into a 'core' > - MFDs need to have more than one child > - This is where the 'Multi' comes in > - Children should straddle different sub-systems > - drivers/net is not enough [0] > - If all of your sub-devices are in 'net' use the platform_* API > - <other stipulations less relevant to this stipulation> ... > > There will always be exceptions, but previous mistakes are not good > justifications for future ones. > > [0] > > .../bindings/net/dsa/nxp,sja1105.yaml | 28 + > .../bindings/net/pcs/snps,dw-xpcs.yaml | 8 + > MAINTAINERS | 2 + > drivers/mfd/mfd-core.c | 11 +- > drivers/net/dsa/sja1105/Kconfig | 2 + > drivers/net/dsa/sja1105/Makefile | 2 +- > drivers/net/dsa/sja1105/sja1105.h | 42 +- > drivers/net/dsa/sja1105/sja1105_main.c | 169 +++--- > drivers/net/dsa/sja1105/sja1105_mdio.c | 507 ------------------ > drivers/net/dsa/sja1105/sja1105_mfd.c | 293 ++++++++++ > drivers/net/dsa/sja1105/sja1105_mfd.h | 11 + > drivers/net/dsa/sja1105/sja1105_spi.c | 113 +++- > drivers/net/mdio/Kconfig | 21 +- > drivers/net/mdio/Makefile | 2 + > drivers/net/mdio/mdio-regmap-simple.c | 77 +++ > drivers/net/mdio/mdio-regmap.c | 7 +- > drivers/net/mdio/mdio-sja1110-cbt1.c | 173 ++++++ > drivers/net/pcs/pcs-xpcs-plat.c | 146 +++-- > drivers/net/pcs/pcs-xpcs.c | 12 + > drivers/net/phy/phylink.c | 75 ++- > include/linux/mdio/mdio-regmap.h | 2 + > include/linux/mfd/core.h | 7 + > include/linux/pcs/pcs-xpcs.h | 1 + > include/linux/phylink.h | 5 + > 24 files changed, 1033 insertions(+), 683 deletions(-) > delete mode 100644 drivers/net/dsa/sja1105/sja1105_mdio.c > create mode 100644 drivers/net/dsa/sja1105/sja1105_mfd.c > create mode 100644 drivers/net/dsa/sja1105/sja1105_mfd.h > create mode 100644 drivers/net/mdio/mdio-regmap-simple.c > create mode 100644 drivers/net/mdio/mdio-sja1110-cbt1.c > > > What OF node would remain for the DSA switch (child) device driver? The same? > > Or are you suggesting that the entire drivers/net/dsa/sja1105/ would > > move to drivers/mfd/? Or? > > See bullet 1.1 above. > > [...] > > > > I don't recall those discussions from 3 years ago, but the Ocelot > > > platform, whatever it may be, seems to have quite a lot more > > > cross-subsystem device support requirements going on than I see here: > > > > > > drivers/i2c/busses/i2c-designware-platdrv.c > > > drivers/irqchip/irq-mscc-ocelot.c > > > drivers/mfd/ocelot-* > > > drivers/net/dsa/ocelot/* > > > drivers/net/ethernet/mscc/ocelot* > > > drivers/net/mdio/mdio-mscc-miim.c > > > drivers/phy/mscc/phy-ocelot-serdes.c > > > drivers/pinctrl/pinctrl-microchip-sgpio.c > > > drivers/pinctrl/pinctrl-ocelot.c > > > drivers/power/reset/ocelot-reset.c > > > drivers/spi/spi-dw-mmio.c > > > net/dsa/tag_ocelot_8021q.c > > > > This is a natural effect of Ocelot being "whatever it may be". It is a > > family of networking SoCs, of which VSC7514 has a MIPS CPU and Linux > > port, where the above drivers are used. The VSC7512 is then a simplified > > variant with the MIPS CPU removed, and the internal components controlled > > externally over SPI. Hence MFD to reuse the same drivers as Linux on > > MIPS (using MMIO) did. This is all that matters, not the quantity. > > From what I can see, Ocelot ticks all of the boxes for MFD API usage, > whereas this submission does not. The fact that the overarching device > provides a similar function is neither here nor there. > > These are the results from my searches of your device: > > git grep -i SJA1110 | grep -v 'net\|arch\|include' > <no results> > > [...] > > > > My point is, you don't seem to have have any of that here. > > > > What do you want to see exactly which is not here? > > > > I have converted three classes of sub-devices on the NXP SJA1110 to MFD > > children in this patch set. Two MDIO buses and an Ethernet PCS for SGMII. > > > > In the SJA1110 memory map, the important resources look something like this: > > > > Name Description Start End > > SWITCH Ethernet Switch Subsystem 0x000000 0x3ffffc > > 100BASE-T1 Internal MDIO bus for 100BASE-T1 PHY (port 5 - 10) 0x704000 0x704ffc > > SGMII1 SGMII Port 1 0x705000 0x705ffc > > SGMII2 SGMII Port 2 0x706000 0x706ffc > > SGMII3 SGMII Port 3 0x707000 0x707ffc > > SGMII4 SGMII Port 4 0x708000 0x708ffc > > 100BASE-TX Internal MDIO bus for 100BASE-TX PHY 0x709000 0x709ffc > > All in drivers/net. > > > ACU Auxiliary Control Unit 0x711000 0x711ffc > > GPIO General Purpose Input/Output 0x712000 0x712ffc > > Where are these drivers? For the GPIO I have no driver yet. For the ACU, there is a reusable group of 4 registers for which I wrote a cascaded interrupt controller driver in 2022. This register group is instantiated multiple times in the SJA1110, which justified a reusable driver. Upstreaming it was blocked by the inability to instantiate it from the main DSA driver using backwards-compatible DT bindings. In any case, on the older generation SJA1105 (common driver with SJA1110), the GPIO and interrupt controller blocks are missing. There is an ACU block, but it handles just pinmux and pad configuration, and the DSA driver programs it directly rather than going through the pinmux subsystem. This highlights a key requirement I have from the API for instantiating sub-devices: that it is sufficiently flexible to split them out of the main device when that starts making sense (we identify a reusable block, or we need to configure it in the device tree, etc). Otherwise, chopping up the switch address space upfront is a huge overhead that may have no practical gains. > > > I need to remind you that my purpose here is not to add drivers in > > breadth for all SJA1110 sub-devices now. > > You'll see from my discussions with Colin, sub-drivers (if they are to > be used for MFD justification (point 3 above), then they must be added > as part of the first submission. Perhaps this isn't an MFD, "yet"? > > [...] IMHO, the concept of being or not being MFD "yet" is silly. Based on the register map, you are, or are not. > > The SGMII blocks are highly reusable IPs licensed from Synopsys, and > > Linux already has DT bindings and a corresponding platform driver for > > the case where their registers are viewed using MMIO. > > This is a good reason for dividing them up into subordinate platform > devices. However, it is not a good use-case of MFD. In it's current > guise, your best bet is to use the platform_* API directly. > > This is a well trodden path and it not challenging: > > % git grep platform_device_add -- arch drivers sound | wc -l > 398 > > [...] > > > In my opinion I do not need to add handling for any other sub-device, > > for the support to be more "cross-system" like for Ocelot. What is here > > is enough for you to decide if this is adequate for MFD or not. > > Currently ... it's not. > > [...] > > Hopefully that helps to clarify my expectations a little. > > TL;DR, this looks like a good candidate for direct platform_* usage. I do have a local branch with platform devices created manually, and yet, I considered the mfd_add_devices() form looked cleaner when submitting. I expect the desire to split up reusable register regions into platform sub-devices to pop up again, so the logic should be available as library code at some level (possibly DSA). Unless you have something against the idea, I'm thinking a good name for this library code would be "nmfd", for "Not MFD". It is like MFD, except: - the parent can simultaneously handle the main function of the device while delegating other regions to sub-devices - the sub-devices can all have drivers in the same subsystem (debatable whether MFD follows this - just to avoid discussions) - their OF nodes don't have to be direct children of the parent.
On Tue, 16 Dec 2025, Vladimir Oltean wrote:
> On Tue, Dec 16, 2025 at 09:18:31AM +0000, Lee Jones wrote:
> > Unless you add/convert more child devices that are outside of net/ and
> > drivers/net AND move the core MFD usage to drivers/mfd/, then we can't
> > conclude that [ this device is suitable for MFD ].
>
> To me, the argument that child devices can't all be under drivers/net/
> is superficial. An mii_bus is very different in purpose from a phylink_pcs
> and from a net_device, yet all 3 live in drivers/net/.
Understood.
> Furthermore, I am looking at schemas such as /devicetree/bindings/mfd/adi,max77541.yaml:
> "MAX77540 is a Power Management IC with 2 buck regulators."
> and I don't understand how it possibly passed this criterion. It is one
> chip with two devices of the same kind, and nothing else.
The MAX77541 has Regulators and an Analog to Digital Converter.
2 makes it Multi and passes criterion.
The ADC is 'hidden' from DT by MFD.
> If moving the core MFD usage to drivers/mfd/ is another hard requirement,
> this is also attacking form rather than substance. You as the MFD
> maintainer can make an appeal to authority and NACK aesthetics you don't
> like, but I just want everyone to be on the same page about this.
My plan, when and if I manage to find a few spare cycles, is to remove
MFD use from outside drivers/mfd. That's been my rule since forever.
Having this in place ensures that the other rules are kept and (mild)
chaos doesn't ensue. The MFD API is trivial to abuse. You wouldn't
believe some of things I've seen over the years. Each value I have is
there for a historical reason.
> > > > There does appear to be at least some level of misunderstanding
> > > > between us. I'm not for one moment suggesting that a switch
> > > > can't be an MFD. If it contains probe-able components that need
> > > > to be split-up across multiple different subsystems, then by all
> > > > means, move the core driver into drivers/mfd/ and register child
> > > > devices 'till your heart's content.
> > >
> > > Are you still speaking generically here, or have you actually
> > > looked at any "nxp,sja1105q" or "nxp,sja1110a" device trees to see
> > > what it would mean for these compatible strings to be probed by a
> > > driver in drivers/mfd?
> >
> > It's not my role to go digging into existing implementations and
> > previous submissions to prove whether a particular submission is
> > suitable for inclusion into MFD.
> >
> > Please put in front of me, in a concise way (please), why you think
> > this is fit for inclusion.
>
> No new information, I think the devices are fit for MFD because of
> their memory map which was shown in the previous reply.
And Andrew's opinion reflects that, so I'm inclined to agree in general
terms.
> > I've explained what is usually required, but I'll (over-)simplify
> > again for clarity:
> >
> > - The mfd_* API call-sites must only exist in drivers/mfd/ -
> > Consumers usually spit out non-system specific logic into a 'core'
> > - MFDs need to have more than one child - This is where the 'Multi'
> > comes in - Children should straddle different sub-systems -
> > drivers/net is not enough [0] - If all of your sub-devices are in
> > 'net' use the platform_* API - <other stipulations less relevant to
> > this stipulation> ...
> >
> > There will always be exceptions, but previous mistakes are not good
> > justifications for future ones.
> >
> > [0]
> >
> > .../bindings/net/dsa/nxp,sja1105.yaml | 28 +
> > .../bindings/net/pcs/snps,dw-xpcs.yaml | 8 + MAINTAINERS
> > | 2 + drivers/mfd/mfd-core.c | 11 +-
> > drivers/net/dsa/sja1105/Kconfig | 2 +
> > drivers/net/dsa/sja1105/Makefile | 2 +-
> > drivers/net/dsa/sja1105/sja1105.h | 42 +-
> > drivers/net/dsa/sja1105/sja1105_main.c | 169 +++---
> > drivers/net/dsa/sja1105/sja1105_mdio.c | 507
> > ------------------ drivers/net/dsa/sja1105/sja1105_mfd.c |
> > 293 ++++++++++ drivers/net/dsa/sja1105/sja1105_mfd.h | 11
> > + drivers/net/dsa/sja1105/sja1105_spi.c | 113 +++-
> > drivers/net/mdio/Kconfig | 21 +-
> > drivers/net/mdio/Makefile | 2 +
> > drivers/net/mdio/mdio-regmap-simple.c | 77 +++
> > drivers/net/mdio/mdio-regmap.c | 7 +-
> > drivers/net/mdio/mdio-sja1110-cbt1.c | 173 ++++++
> > drivers/net/pcs/pcs-xpcs-plat.c | 146 +++--
> > drivers/net/pcs/pcs-xpcs.c | 12 +
> > drivers/net/phy/phylink.c | 75 ++-
> > include/linux/mdio/mdio-regmap.h | 2 +
> > include/linux/mfd/core.h | 7 +
> > include/linux/pcs/pcs-xpcs.h | 1 +
> > include/linux/phylink.h | 5 + 24 files
> > changed, 1033 insertions(+), 683 deletions(-) delete mode 100644
> > drivers/net/dsa/sja1105/sja1105_mdio.c create mode 100644
> > drivers/net/dsa/sja1105/sja1105_mfd.c create mode 100644
> > drivers/net/dsa/sja1105/sja1105_mfd.h create mode 100644
> > drivers/net/mdio/mdio-regmap-simple.c create mode 100644
> > drivers/net/mdio/mdio-sja1110-cbt1.c
> >
> > > What OF node would remain for the DSA switch (child) device
> > > driver? The same? Or are you suggesting that the entire
> > > drivers/net/dsa/sja1105/ would move to drivers/mfd/? Or?
> >
> > See bullet 1.1 above.
> >
> > [...]
> >
> > > > I don't recall those discussions from 3 years ago, but the
> > > > Ocelot platform, whatever it may be, seems to have quite a lot
> > > > more cross-subsystem device support requirements going on than I
> > > > see here:
> > > >
> > > > drivers/i2c/busses/i2c-designware-platdrv.c
> > > > drivers/irqchip/irq-mscc-ocelot.c drivers/mfd/ocelot-*
> > > > drivers/net/dsa/ocelot/* drivers/net/ethernet/mscc/ocelot*
> > > > drivers/net/mdio/mdio-mscc-miim.c
> > > > drivers/phy/mscc/phy-ocelot-serdes.c
> > > > drivers/pinctrl/pinctrl-microchip-sgpio.c
> > > > drivers/pinctrl/pinctrl-ocelot.c
> > > > drivers/power/reset/ocelot-reset.c drivers/spi/spi-dw-mmio.c
> > > > net/dsa/tag_ocelot_8021q.c
> > >
> > > This is a natural effect of Ocelot being "whatever it may be". It
> > > is a family of networking SoCs, of which VSC7514 has a MIPS CPU
> > > and Linux port, where the above drivers are used. The VSC7512 is
> > > then a simplified variant with the MIPS CPU removed, and the
> > > internal components controlled externally over SPI. Hence MFD to
> > > reuse the same drivers as Linux on MIPS (using MMIO) did. This is
> > > all that matters, not the quantity.
> >
> > From what I can see, Ocelot ticks all of the boxes for MFD API
> > usage, whereas this submission does not. The fact that the
> > overarching device provides a similar function is neither here nor
> > there.
> >
> > These are the results from my searches of your device:
> >
> > git grep -i SJA1110 | grep -v 'net\|arch\|include' <no results>
> >
> > [...]
> >
> > > > My point is, you don't seem to have have any of that here.
> > >
> > > What do you want to see exactly which is not here?
> > >
> > > I have converted three classes of sub-devices on the NXP SJA1110
> > > to MFD children in this patch set. Two MDIO buses and an Ethernet
> > > PCS for SGMII.
> > >
> > > In the SJA1110 memory map, the important resources look something
> > > like this:
> > >
> > > Name Description
> > > Start End SWITCH Ethernet Switch Subsystem
> > > 0x000000 0x3ffffc 100BASE-T1 Internal MDIO bus for 100BASE-T1
> > > PHY (port 5 - 10) 0x704000 0x704ffc SGMII1 SGMII Port 1
> > > 0x705000 0x705ffc SGMII2 SGMII Port 2
> > > 0x706000 0x706ffc SGMII3 SGMII Port 3
> > > 0x707000 0x707ffc SGMII4 SGMII Port 4
> > > 0x708000 0x708ffc 100BASE-TX Internal MDIO bus for 100BASE-TX
> > > PHY 0x709000 0x709ffc
> >
> > All in drivers/net.
> >
> > > ACU Auxiliary Control Unit
> > > 0x711000 0x711ffc GPIO General Purpose Input/Output
> > > 0x712000 0x712ffc
> >
> > Where are these drivers?
>
> For the GPIO I have no driver yet.
>
> For the ACU, there is a reusable group of 4 registers for which I
> wrote a cascaded interrupt controller driver in 2022. This register
> group is instantiated multiple times in the SJA1110, which justified a
> reusable driver.
>
> Upstreaming it was blocked by the inability to instantiate it from the
> main DSA driver using backwards-compatible DT bindings.
>
> In any case, on the older generation SJA1105 (common driver with
> SJA1110), the GPIO and interrupt controller blocks are missing. There
> is an ACU block, but it handles just pinmux and pad configuration, and
> the DSA driver programs it directly rather than going through the
> pinmux subsystem.
>
> This highlights a key requirement I have from the API for
> instantiating sub-devices: that it is sufficiently flexible to split
> them out of the main device when that starts making sense (we identify
> a reusable block, or we need to configure it in the device tree, etc).
> Otherwise, chopping up the switch address space upfront is a huge
> overhead that may have no practical gains.
I certainly understand the challenges.
However, from my PoV, if you are instantiating one driver, even if it
does a bunch of different things which _could_ be split-up into all
sorts of far reaching subsystems, it's still one driver and therefore
does not meet the criteria for inclusion into MFD.
I had to go and remind myself of your DT:
ethernet-switch@0 {
compatible = "nxp,sja1110a";
mdios {
mdio@0 {
compatible = "nxp,sja1110-base-t1-mdio";
};
mdio@1 {
compatible = "nxp,sja1110-base-tx-mdio";
};
};
};
To my untrained eye, this looks like two instances of a MDIO device.
Are they truly different enough to be classified for "Multi"?
> > > I need to remind you that my purpose here is not to add drivers in
> > > breadth for all SJA1110 sub-devices now.
> >
> > You'll see from my discussions with Colin, sub-drivers (if they are
> > to be used for MFD justification (point 3 above), then they must be
> > added as part of the first submission. Perhaps this isn't an MFD,
> > "yet"?
> >
> > [...]
>
> IMHO, the concept of being or not being MFD "yet" is silly. Based on
> the register map, you are, or are not.
Perhaps I didn't explain this very well. What I'm alluding to here is
that perhaps this a collection of different devices that may well fit
comfortably with the remit of MFD. However, I haven't seen any
compelling evidence of that in this current submission.
As an example, when contributors submit an MFD core driver with only one
device, let's say a few Regulators but promise that the device is
actually capable of operating as a Watchdog, a Real-Time Clock and a
Power-on Key, only they haven't authored the drivers for those yet. The
driver get NACKed until at least one other piece of functionality is
available. Else the "Multi" box isn't ticked and therefore does not
qualify for inclusion.
The "yet" part was alluding to the fact that this may be the case here.
> > > The SGMII blocks are highly reusable IPs licensed from Synopsys,
> > > and Linux already has DT bindings and a corresponding platform
> > > driver for the case where their registers are viewed using MMIO.
> >
> > This is a good reason for dividing them up into subordinate platform
> > devices. However, it is not a good use-case of MFD. In it's
> > current guise, your best bet is to use the platform_* API directly.
> >
> > This is a well trodden path and it not challenging:
> >
> > % git grep platform_device_add -- arch drivers sound | wc -l 398
> >
> > [...]
> >
> > > In my opinion I do not need to add handling for any other
> > > sub-device, for the support to be more "cross-system" like for
> > > Ocelot. What is here is enough for you to decide if this is
> > > adequate for MFD or not.
> >
> > Currently ... it's not.
> >
> > [...]
> >
> > Hopefully that helps to clarify my expectations a little.
> >
> > TL;DR, this looks like a good candidate for direct platform_* usage.
>
> I do have a local branch with platform devices created manually, and
> yet, I considered the mfd_add_devices() form looked cleaner when
> submitting.
>
> I expect the desire to split up reusable register regions into
> platform sub-devices to pop up again, so the logic should be available
> as library code at some level (possibly DSA).
>
> Unless you have something against the idea, I'm thinking a good name
> for this library code would be "nmfd", for "Not MFD". It is like MFD,
> except: - the parent can simultaneously handle the main function of
> the device while delegating other regions to sub-devices - the
> sub-devices can all have drivers in the same subsystem (debatable
> whether MFD follows this - just to avoid discussions) - their OF nodes
> don't have to be direct children of the parent.
Well, we already have Simple MFD which works for some basic use-cases.
When I've thought about replacing the existing occurrences of the MFD
API being used outside of drivers/mfd, I have often thought of a
platform_add_device_simple() call which I believe would do what most
people of these use-cases actually want.
--
Lee Jones [李琼斯]
Hi Lee,
Thanks for returning to this conversation.
On Fri, Jan 09, 2026 at 10:31:05AM +0000, Lee Jones wrote:
> On Tue, 16 Dec 2025, Vladimir Oltean wrote:
>
> > On Tue, Dec 16, 2025 at 09:18:31AM +0000, Lee Jones wrote:
> > > Unless you add/convert more child devices that are outside of net/ and
> > > drivers/net AND move the core MFD usage to drivers/mfd/, then we can't
> > > conclude that [ this device is suitable for MFD ].
> >
> > To me, the argument that child devices can't all be under drivers/net/
> > is superficial. An mii_bus is very different in purpose from a phylink_pcs
> > and from a net_device, yet all 3 live in drivers/net/.
>
> Understood.
>
> > Furthermore, I am looking at schemas such as /devicetree/bindings/mfd/adi,max77541.yaml:
> > "MAX77540 is a Power Management IC with 2 buck regulators."
> > and I don't understand how it possibly passed this criterion. It is one
> > chip with two devices of the same kind, and nothing else.
>
> The MAX77541 has Regulators and an Analog to Digital Converter.
>
> 2 makes it Multi and passes criterion.
>
> The ADC is 'hidden' from DT by MFD.
Yes, but MAX77540 doesn't have the ADC. Anyway.
> > If moving the core MFD usage to drivers/mfd/ is another hard requirement,
> > this is also attacking form rather than substance. You as the MFD
> > maintainer can make an appeal to authority and NACK aesthetics you don't
> > like, but I just want everyone to be on the same page about this.
>
> My plan, when and if I manage to find a few spare cycles, is to remove
> MFD use from outside drivers/mfd. That's been my rule since forever.
> Having this in place ensures that the other rules are kept and (mild)
> chaos doesn't ensue. The MFD API is trivial to abuse. You wouldn't
> believe some of things I've seen over the years. Each value I have is
> there for a historical reason.
If you're also of the opinion that MFD is a Linux-specific
implementation detail and a figment of our imagination as developers,
then I certainly don't understand why Documentation/devicetree/bindings/mfd/
exists for this separate device class that is MFD, and why you don't
liberalize access to mfd_add_devices() instead.
> > > > > There does appear to be at least some level of misunderstanding
> > > > > between us. I'm not for one moment suggesting that a switch
> > > > > can't be an MFD. If it contains probe-able components that need
> > > > > to be split-up across multiple different subsystems, then by all
> > > > > means, move the core driver into drivers/mfd/ and register child
> > > > > devices 'till your heart's content.
> > > >
> > > > Are you still speaking generically here, or have you actually
> > > > looked at any "nxp,sja1105q" or "nxp,sja1110a" device trees to see
> > > > what it would mean for these compatible strings to be probed by a
> > > > driver in drivers/mfd?
> > >
> > > It's not my role to go digging into existing implementations and
> > > previous submissions to prove whether a particular submission is
> > > suitable for inclusion into MFD.
> > >
> > > Please put in front of me, in a concise way (please), why you think
> > > this is fit for inclusion.
> >
> > No new information, I think the devices are fit for MFD because of
> > their memory map which was shown in the previous reply.
>
> And Andrew's opinion reflects that, so I'm inclined to agree in general
> terms.
>
> > > I've explained what is usually required, but I'll (over-)simplify
> > > again for clarity:
> > >
> > > - The mfd_* API call-sites must only exist in drivers/mfd/ -
> > > Consumers usually spit out non-system specific logic into a 'core'
> > > - MFDs need to have more than one child - This is where the 'Multi'
> > > comes in - Children should straddle different sub-systems -
> > > drivers/net is not enough [0] - If all of your sub-devices are in
> > > 'net' use the platform_* API - <other stipulations less relevant to
> > > this stipulation> ...
> > >
> > > There will always be exceptions, but previous mistakes are not good
> > > justifications for future ones.
> > >
> > > [0]
> > >
> > > .../bindings/net/dsa/nxp,sja1105.yaml | 28 +
> > > .../bindings/net/pcs/snps,dw-xpcs.yaml | 8 + MAINTAINERS
> > > | 2 + drivers/mfd/mfd-core.c | 11 +-
> > > drivers/net/dsa/sja1105/Kconfig | 2 +
> > > drivers/net/dsa/sja1105/Makefile | 2 +-
> > > drivers/net/dsa/sja1105/sja1105.h | 42 +-
> > > drivers/net/dsa/sja1105/sja1105_main.c | 169 +++---
> > > drivers/net/dsa/sja1105/sja1105_mdio.c | 507
> > > ------------------ drivers/net/dsa/sja1105/sja1105_mfd.c |
> > > 293 ++++++++++ drivers/net/dsa/sja1105/sja1105_mfd.h | 11
> > > + drivers/net/dsa/sja1105/sja1105_spi.c | 113 +++-
> > > drivers/net/mdio/Kconfig | 21 +-
> > > drivers/net/mdio/Makefile | 2 +
> > > drivers/net/mdio/mdio-regmap-simple.c | 77 +++
> > > drivers/net/mdio/mdio-regmap.c | 7 +-
> > > drivers/net/mdio/mdio-sja1110-cbt1.c | 173 ++++++
> > > drivers/net/pcs/pcs-xpcs-plat.c | 146 +++--
> > > drivers/net/pcs/pcs-xpcs.c | 12 +
> > > drivers/net/phy/phylink.c | 75 ++-
> > > include/linux/mdio/mdio-regmap.h | 2 +
> > > include/linux/mfd/core.h | 7 +
> > > include/linux/pcs/pcs-xpcs.h | 1 +
> > > include/linux/phylink.h | 5 + 24 files
> > > changed, 1033 insertions(+), 683 deletions(-) delete mode 100644
> > > drivers/net/dsa/sja1105/sja1105_mdio.c create mode 100644
> > > drivers/net/dsa/sja1105/sja1105_mfd.c create mode 100644
> > > drivers/net/dsa/sja1105/sja1105_mfd.h create mode 100644
> > > drivers/net/mdio/mdio-regmap-simple.c create mode 100644
> > > drivers/net/mdio/mdio-sja1110-cbt1.c
> > >
> > > > What OF node would remain for the DSA switch (child) device
> > > > driver? The same? Or are you suggesting that the entire
> > > > drivers/net/dsa/sja1105/ would move to drivers/mfd/? Or?
> > >
> > > See bullet 1.1 above.
> > >
> > > [...]
> > >
> > > > > I don't recall those discussions from 3 years ago, but the
> > > > > Ocelot platform, whatever it may be, seems to have quite a lot
> > > > > more cross-subsystem device support requirements going on than I
> > > > > see here:
> > > > >
> > > > > drivers/i2c/busses/i2c-designware-platdrv.c
> > > > > drivers/irqchip/irq-mscc-ocelot.c drivers/mfd/ocelot-*
> > > > > drivers/net/dsa/ocelot/* drivers/net/ethernet/mscc/ocelot*
> > > > > drivers/net/mdio/mdio-mscc-miim.c
> > > > > drivers/phy/mscc/phy-ocelot-serdes.c
> > > > > drivers/pinctrl/pinctrl-microchip-sgpio.c
> > > > > drivers/pinctrl/pinctrl-ocelot.c
> > > > > drivers/power/reset/ocelot-reset.c drivers/spi/spi-dw-mmio.c
> > > > > net/dsa/tag_ocelot_8021q.c
> > > >
> > > > This is a natural effect of Ocelot being "whatever it may be". It
> > > > is a family of networking SoCs, of which VSC7514 has a MIPS CPU
> > > > and Linux port, where the above drivers are used. The VSC7512 is
> > > > then a simplified variant with the MIPS CPU removed, and the
> > > > internal components controlled externally over SPI. Hence MFD to
> > > > reuse the same drivers as Linux on MIPS (using MMIO) did. This is
> > > > all that matters, not the quantity.
> > >
> > > From what I can see, Ocelot ticks all of the boxes for MFD API
> > > usage, whereas this submission does not. The fact that the
> > > overarching device provides a similar function is neither here nor
> > > there.
> > >
> > > These are the results from my searches of your device:
> > >
> > > git grep -i SJA1110 | grep -v 'net\|arch\|include' <no results>
> > >
> > > [...]
> > >
> > > > > My point is, you don't seem to have have any of that here.
> > > >
> > > > What do you want to see exactly which is not here?
> > > >
> > > > I have converted three classes of sub-devices on the NXP SJA1110
> > > > to MFD children in this patch set. Two MDIO buses and an Ethernet
> > > > PCS for SGMII.
> > > >
> > > > In the SJA1110 memory map, the important resources look something
> > > > like this:
> > > >
> > > > Name Description
> > > > Start End SWITCH Ethernet Switch Subsystem
> > > > 0x000000 0x3ffffc 100BASE-T1 Internal MDIO bus for 100BASE-T1
> > > > PHY (port 5 - 10) 0x704000 0x704ffc SGMII1 SGMII Port 1
> > > > 0x705000 0x705ffc SGMII2 SGMII Port 2
> > > > 0x706000 0x706ffc SGMII3 SGMII Port 3
> > > > 0x707000 0x707ffc SGMII4 SGMII Port 4
> > > > 0x708000 0x708ffc 100BASE-TX Internal MDIO bus for 100BASE-TX
> > > > PHY 0x709000 0x709ffc
> > >
> > > All in drivers/net.
> > >
> > > > ACU Auxiliary Control Unit
> > > > 0x711000 0x711ffc GPIO General Purpose Input/Output
> > > > 0x712000 0x712ffc
> > >
> > > Where are these drivers?
> >
> > For the GPIO I have no driver yet.
> >
> > For the ACU, there is a reusable group of 4 registers for which I
> > wrote a cascaded interrupt controller driver in 2022. This register
> > group is instantiated multiple times in the SJA1110, which justified a
> > reusable driver.
> >
> > Upstreaming it was blocked by the inability to instantiate it from the
> > main DSA driver using backwards-compatible DT bindings.
> >
> > In any case, on the older generation SJA1105 (common driver with
> > SJA1110), the GPIO and interrupt controller blocks are missing. There
> > is an ACU block, but it handles just pinmux and pad configuration, and
> > the DSA driver programs it directly rather than going through the
> > pinmux subsystem.
> >
> > This highlights a key requirement I have from the API for
> > instantiating sub-devices: that it is sufficiently flexible to split
> > them out of the main device when that starts making sense (we identify
> > a reusable block, or we need to configure it in the device tree, etc).
> > Otherwise, chopping up the switch address space upfront is a huge
> > overhead that may have no practical gains.
>
> I certainly understand the challenges.
>
> However, from my PoV, if you are instantiating one driver, even if it
> does a bunch of different things which _could_ be split-up into all
> sorts of far reaching subsystems, it's still one driver and therefore
> does not meet the criteria for inclusion into MFD.
>
> I had to go and remind myself of your DT:
>
> ethernet-switch@0 {
> compatible = "nxp,sja1110a";
>
> mdios {
> mdio@0 {
> compatible = "nxp,sja1110-base-t1-mdio";
> };
>
> mdio@1 {
> compatible = "nxp,sja1110-base-tx-mdio";
> };
> };
> };
>
> To my untrained eye, this looks like two instances of a MDIO device.
>
> Are they truly different enough to be classified for "Multi"?
Careful about terms, these are MDIO "buses" and not MDIO "devices"
(children of those buses).
Let me reframe what I think you are saying.
If the aesthetics of the dt-bindings of my SPI device were like this (1):
spi {
mfd@0 {
^ reg = <0>; // SPI chip select
| #address-cells = <1>;
| #size-cells = <1>;
|
| ethernet-switch@0 { // SWITCH region (0x000000 0x3ffffc) ^
| reg = <0x000000 0x400000>; | DSA probes only here
| }; v
|
| mdio@704000 { // 100BASE-T1 region (0x704000 0x704ffc)
| reg = <0x704000 0x1000>;
| }
|
Entire SPI | ethernet-pcs@705000 { // SGMII1 region (0x705000 0x705ffc)
device address | reg = <0x705000 0x1000>;
space | }
(0x0-0x71FFFC), |
up for grabs | ethernet-pcs@706000 { // SGMII2 region (0x706000 0x706ffc)
by sub-devices | reg = <0x706000 0x1000>;
| };
|
| ethernet-pcs@707000 { // SGMII3 region (0x707000 0x707ffc)
| reg = <0x707000 0x1000>;
| };
|
| ethernet-pcs@708000 { // SGMII4 region (0x708000 0x708ffc)
| reg = <0x708000 0x1000>;
| };
|
| mdio@709000 { // 100BASE-TX region (0x709000 0x709ffc)
| reg = <0x709000 0x1000>;
| };
v };
};
then you wouldn't have had any issue about this not being MFD, correct?
I think this is an important base fact to establish.
It looks fairly similar to Colin Foster's bindings for VSC7512, save for
the fact that the sub-devices are slightly more varied (which is inconsequential,
as Andrew seems to agree).
However, the same physical reality is being described in these _actual_
dt-bindings (2):
spi {
ethernet-switch@0 { // DSA probes here
^ reg = <0>; // SPI chip select
|
| // Legacy sub-devices (presently registered by DSA driver),
| // already established dt-binding, proposal is to keep bindings unchanged,
| // but to register using MFD
| mdios {
| mdio@0 { // 100BASE-T1 region (0x704000 0x704ffc)
| compatible = "nxp,sja1110-base-t1-mdio";
| };
|
| mdio@1 { // 100BASE-TX region (0x709000 0x709ffc)
| compatible = "nxp,sja1110-base-tx-mdio";
| };
| };
|
| regs { // Proposed binding addition, anything here is MFD child ^
| #address-cells = <1>; |
Entire SPI | #size-cells = <1>; |
device address | |
space | ethernet-pcs@705000 { // SGMII1 region (0x705000 0x705ffc) |
(0x0-0x71FFFC) | reg = <0x705000 0x1000>; |
owned by DSA | } |
driver | |
| ethernet-pcs@706000 { // SGMII2 region (0x706000 0x706ffc) | Entire SPI
| reg = <0x706000 0x1000>; | device address
| }; | space again
| | (0x0-0x71FFFC)
| ethernet-pcs@707000 { // SGMII3 region (0x707000 0x707ffc) | up for grabs
| reg = <0x707000 0x1000>; | by sub-devices
| }; |
| |
| ethernet-pcs@708000 { // SGMII4 region (0x708000 0x708ffc) |
| reg = <0x708000 0x1000>; |
| }; |
| }; v
v };
};
Your issue is that, when looking at these real dt-bindings,
superficially the MDIO buses don't "look" like MFD.
To which, yes, I have no objection, they don't look like MFD because
they were written as additions on top of the DSA schema structure, not
according to the MFD schema.
In reality it doesn't matter much where the MDIO bus nodes are (they
could have been under "regs" as well, or under "mfd@0"), because DSA
ports get references to their children using phandles. It's just that
they are _already_ where they are, and moving them would be an avoidable
breaking change.
> > > > I need to remind you that my purpose here is not to add drivers in
> > > > breadth for all SJA1110 sub-devices now.
> > >
> > > You'll see from my discussions with Colin, sub-drivers (if they are
> > > to be used for MFD justification (point 3 above), then they must be
> > > added as part of the first submission. Perhaps this isn't an MFD,
> > > "yet"?
> > >
> > > [...]
> >
> > IMHO, the concept of being or not being MFD "yet" is silly. Based on
> > the register map, you are, or are not.
>
> Perhaps I didn't explain this very well. What I'm alluding to here is
> that perhaps this a collection of different devices that may well fit
> comfortably with the remit of MFD. However, I haven't seen any
> compelling evidence of that in this current submission.
>
> As an example, when contributors submit an MFD core driver with only one
> device, let's say a few Regulators but promise that the device is
> actually capable of operating as a Watchdog, a Real-Time Clock and a
> Power-on Key, only they haven't authored the drivers for those yet. The
> driver get NACKed until at least one other piece of functionality is
> available. Else the "Multi" box isn't ticked and therefore does not
> qualify for inclusion.
Exactly. DSA drivers get more developed with new each new hardware
generation, and you wouldn't want to see an MFD driver + its bindings
"just in case" new sub-devices will appear, when currently the DSA
switch is the only component supported by Linux (and maybe its internal
MDIO bus).
You provided exactly the reason why the dt-bindings of SJA1110 look like (2),
yet you dislike they don't look like (1) in order to fit the narrow
understanding of how the MFD API should be used.
> The "yet" part was alluding to the fact that this may be the case here.
Yes, so in my understanding it's MFD if it uses mfd_add_devices() and
it's not MFD if it doesn't.
> > > > The SGMII blocks are highly reusable IPs licensed from Synopsys,
> > > > and Linux already has DT bindings and a corresponding platform
> > > > driver for the case where their registers are viewed using MMIO.
> > >
> > > This is a good reason for dividing them up into subordinate platform
> > > devices. However, it is not a good use-case of MFD. In it's
> > > current guise, your best bet is to use the platform_* API directly.
> > >
> > > This is a well trodden path and it not challenging:
> > >
> > > % git grep platform_device_add -- arch drivers sound | wc -l 398
> > >
> > > [...]
> > >
> > > > In my opinion I do not need to add handling for any other
> > > > sub-device, for the support to be more "cross-system" like for
> > > > Ocelot. What is here is enough for you to decide if this is
> > > > adequate for MFD or not.
> > >
> > > Currently ... it's not.
> > >
> > > [...]
> > >
> > > Hopefully that helps to clarify my expectations a little.
> > >
> > > TL;DR, this looks like a good candidate for direct platform_* usage.
> >
> > I do have a local branch with platform devices created manually, and
> > yet, I considered the mfd_add_devices() form looked cleaner when
> > submitting.
> >
> > I expect the desire to split up reusable register regions into
> > platform sub-devices to pop up again, so the logic should be available
> > as library code at some level (possibly DSA).
> >
> > Unless you have something against the idea, I'm thinking a good name
> > for this library code would be "nmfd", for "Not MFD". It is like MFD,
> > except: - the parent can simultaneously handle the main function of
> > the device while delegating other regions to sub-devices - the
> > sub-devices can all have drivers in the same subsystem (debatable
> > whether MFD follows this - just to avoid discussions) - their OF nodes
> > don't have to be direct children of the parent.
>
> Well, we already have Simple MFD which works for some basic use-cases.
>
> When I've thought about replacing the existing occurrences of the MFD
> API being used outside of drivers/mfd, I have often thought of a
> platform_add_device_simple() call which I believe would do what most
> people of these use-cases actually want.
Would this platform_add_device_simple() share or duplicate code with
mfd_add_devices()? Why not just liberalize mfd_add_devices() (the
simplest solution)?
On Fri, 09 Jan 2026, Vladimir Oltean wrote:
> Hi Lee,
>
> Thanks for returning to this conversation.
>
> On Fri, Jan 09, 2026 at 10:31:05AM +0000, Lee Jones wrote:
> > On Tue, 16 Dec 2025, Vladimir Oltean wrote:
> >
> > > On Tue, Dec 16, 2025 at 09:18:31AM +0000, Lee Jones wrote:
> > > > Unless you add/convert more child devices that are outside of net/ and
> > > > drivers/net AND move the core MFD usage to drivers/mfd/, then we can't
> > > > conclude that [ this device is suitable for MFD ].
> > >
> > > To me, the argument that child devices can't all be under drivers/net/
> > > is superficial. An mii_bus is very different in purpose from a phylink_pcs
> > > and from a net_device, yet all 3 live in drivers/net/.
> >
> > Understood.
> >
> > > Furthermore, I am looking at schemas such as /devicetree/bindings/mfd/adi,max77541.yaml:
> > > "MAX77540 is a Power Management IC with 2 buck regulators."
> > > and I don't understand how it possibly passed this criterion. It is one
> > > chip with two devices of the same kind, and nothing else.
> >
> > The MAX77541 has Regulators and an Analog to Digital Converter.
> >
> > 2 makes it Multi and passes criterion.
> >
> > The ADC is 'hidden' from DT by MFD.
>
> Yes, but MAX77540 doesn't have the ADC. Anyway.
MAX77540 wouldn't have been accepted on its own.
It was effectively carried in by MAX77541 support.
> > > If moving the core MFD usage to drivers/mfd/ is another hard requirement,
> > > this is also attacking form rather than substance. You as the MFD
> > > maintainer can make an appeal to authority and NACK aesthetics you don't
> > > like, but I just want everyone to be on the same page about this.
> >
> > My plan, when and if I manage to find a few spare cycles, is to remove
> > MFD use from outside drivers/mfd. That's been my rule since forever.
> > Having this in place ensures that the other rules are kept and (mild)
> > chaos doesn't ensue. The MFD API is trivial to abuse. You wouldn't
> > believe some of things I've seen over the years. Each value I have is
> > there for a historical reason.
>
> If you're also of the opinion that MFD is a Linux-specific
> implementation detail and a figment of our imagination as developers,
> then I certainly don't understand why Documentation/devicetree/bindings/mfd/
> exists for this separate device class that is MFD, and why you don't
> liberalize access to mfd_add_devices() instead.
The first point is a good one. It mostly exists for historical
reasons and for want of a better place to locate the documentation.
I've explained why liberalising the mfd_*() API is a bad idea. "Clever"
developers like to do some pretty crazy stuff involving the use of
multiple device registration APIs simultaneously. I've also seen some
bonkers methods of dynamically populating MFD cells [*ahem* Patch 8
=;-)] and various other things. Keeping the API in-house allows me to
keep things simple, easily readable and maintainable.
> > > > > > There does appear to be at least some level of misunderstanding
> > > > > > between us. I'm not for one moment suggesting that a switch
> > > > > > can't be an MFD. If it contains probe-able components that need
> > > > > > to be split-up across multiple different subsystems, then by all
> > > > > > means, move the core driver into drivers/mfd/ and register child
> > > > > > devices 'till your heart's content.
> > > > >
> > > > > Are you still speaking generically here, or have you actually
> > > > > looked at any "nxp,sja1105q" or "nxp,sja1110a" device trees to see
> > > > > what it would mean for these compatible strings to be probed by a
> > > > > driver in drivers/mfd?
> > > >
> > > > It's not my role to go digging into existing implementations and
> > > > previous submissions to prove whether a particular submission is
> > > > suitable for inclusion into MFD.
> > > >
> > > > Please put in front of me, in a concise way (please), why you think
> > > > this is fit for inclusion.
> > >
> > > No new information, I think the devices are fit for MFD because of
> > > their memory map which was shown in the previous reply.
> >
> > And Andrew's opinion reflects that, so I'm inclined to agree in general
> > terms.
> >
> > > > I've explained what is usually required, but I'll (over-)simplify
> > > > again for clarity:
> > > >
> > > > - The mfd_* API call-sites must only exist in drivers/mfd/ -
> > > > Consumers usually spit out non-system specific logic into a 'core'
> > > > - MFDs need to have more than one child - This is where the 'Multi'
> > > > comes in - Children should straddle different sub-systems -
> > > > drivers/net is not enough [0] - If all of your sub-devices are in
> > > > 'net' use the platform_* API - <other stipulations less relevant to
> > > > this stipulation> ...
> > > >
> > > > There will always be exceptions, but previous mistakes are not good
> > > > justifications for future ones.
> > > >
> > > > [0]
> > > >
> > > > .../bindings/net/dsa/nxp,sja1105.yaml | 28 +
> > > > .../bindings/net/pcs/snps,dw-xpcs.yaml | 8 + MAINTAINERS
> > > > | 2 + drivers/mfd/mfd-core.c | 11 +-
> > > > drivers/net/dsa/sja1105/Kconfig | 2 +
> > > > drivers/net/dsa/sja1105/Makefile | 2 +-
> > > > drivers/net/dsa/sja1105/sja1105.h | 42 +-
> > > > drivers/net/dsa/sja1105/sja1105_main.c | 169 +++---
> > > > drivers/net/dsa/sja1105/sja1105_mdio.c | 507
> > > > ------------------ drivers/net/dsa/sja1105/sja1105_mfd.c |
> > > > 293 ++++++++++ drivers/net/dsa/sja1105/sja1105_mfd.h | 11
> > > > + drivers/net/dsa/sja1105/sja1105_spi.c | 113 +++-
> > > > drivers/net/mdio/Kconfig | 21 +-
> > > > drivers/net/mdio/Makefile | 2 +
> > > > drivers/net/mdio/mdio-regmap-simple.c | 77 +++
> > > > drivers/net/mdio/mdio-regmap.c | 7 +-
> > > > drivers/net/mdio/mdio-sja1110-cbt1.c | 173 ++++++
> > > > drivers/net/pcs/pcs-xpcs-plat.c | 146 +++--
> > > > drivers/net/pcs/pcs-xpcs.c | 12 +
> > > > drivers/net/phy/phylink.c | 75 ++-
> > > > include/linux/mdio/mdio-regmap.h | 2 +
> > > > include/linux/mfd/core.h | 7 +
> > > > include/linux/pcs/pcs-xpcs.h | 1 +
> > > > include/linux/phylink.h | 5 + 24 files
> > > > changed, 1033 insertions(+), 683 deletions(-) delete mode 100644
> > > > drivers/net/dsa/sja1105/sja1105_mdio.c create mode 100644
> > > > drivers/net/dsa/sja1105/sja1105_mfd.c create mode 100644
> > > > drivers/net/dsa/sja1105/sja1105_mfd.h create mode 100644
> > > > drivers/net/mdio/mdio-regmap-simple.c create mode 100644
> > > > drivers/net/mdio/mdio-sja1110-cbt1.c
> > > >
> > > > > What OF node would remain for the DSA switch (child) device
> > > > > driver? The same? Or are you suggesting that the entire
> > > > > drivers/net/dsa/sja1105/ would move to drivers/mfd/? Or?
> > > >
> > > > See bullet 1.1 above.
> > > >
> > > > [...]
> > > >
> > > > > > I don't recall those discussions from 3 years ago, but the
> > > > > > Ocelot platform, whatever it may be, seems to have quite a lot
> > > > > > more cross-subsystem device support requirements going on than I
> > > > > > see here:
> > > > > >
> > > > > > drivers/i2c/busses/i2c-designware-platdrv.c
> > > > > > drivers/irqchip/irq-mscc-ocelot.c drivers/mfd/ocelot-*
> > > > > > drivers/net/dsa/ocelot/* drivers/net/ethernet/mscc/ocelot*
> > > > > > drivers/net/mdio/mdio-mscc-miim.c
> > > > > > drivers/phy/mscc/phy-ocelot-serdes.c
> > > > > > drivers/pinctrl/pinctrl-microchip-sgpio.c
> > > > > > drivers/pinctrl/pinctrl-ocelot.c
> > > > > > drivers/power/reset/ocelot-reset.c drivers/spi/spi-dw-mmio.c
> > > > > > net/dsa/tag_ocelot_8021q.c
> > > > >
> > > > > This is a natural effect of Ocelot being "whatever it may be". It
> > > > > is a family of networking SoCs, of which VSC7514 has a MIPS CPU
> > > > > and Linux port, where the above drivers are used. The VSC7512 is
> > > > > then a simplified variant with the MIPS CPU removed, and the
> > > > > internal components controlled externally over SPI. Hence MFD to
> > > > > reuse the same drivers as Linux on MIPS (using MMIO) did. This is
> > > > > all that matters, not the quantity.
> > > >
> > > > From what I can see, Ocelot ticks all of the boxes for MFD API
> > > > usage, whereas this submission does not. The fact that the
> > > > overarching device provides a similar function is neither here nor
> > > > there.
> > > >
> > > > These are the results from my searches of your device:
> > > >
> > > > git grep -i SJA1110 | grep -v 'net\|arch\|include' <no results>
> > > >
> > > > [...]
> > > >
> > > > > > My point is, you don't seem to have have any of that here.
> > > > >
> > > > > What do you want to see exactly which is not here?
> > > > >
> > > > > I have converted three classes of sub-devices on the NXP SJA1110
> > > > > to MFD children in this patch set. Two MDIO buses and an Ethernet
> > > > > PCS for SGMII.
> > > > >
> > > > > In the SJA1110 memory map, the important resources look something
> > > > > like this:
> > > > >
> > > > > Name Description
> > > > > Start End SWITCH Ethernet Switch Subsystem
> > > > > 0x000000 0x3ffffc 100BASE-T1 Internal MDIO bus for 100BASE-T1
> > > > > PHY (port 5 - 10) 0x704000 0x704ffc SGMII1 SGMII Port 1
> > > > > 0x705000 0x705ffc SGMII2 SGMII Port 2
> > > > > 0x706000 0x706ffc SGMII3 SGMII Port 3
> > > > > 0x707000 0x707ffc SGMII4 SGMII Port 4
> > > > > 0x708000 0x708ffc 100BASE-TX Internal MDIO bus for 100BASE-TX
> > > > > PHY 0x709000 0x709ffc
> > > >
> > > > All in drivers/net.
> > > >
> > > > > ACU Auxiliary Control Unit
> > > > > 0x711000 0x711ffc GPIO General Purpose Input/Output
> > > > > 0x712000 0x712ffc
> > > >
> > > > Where are these drivers?
> > >
> > > For the GPIO I have no driver yet.
> > >
> > > For the ACU, there is a reusable group of 4 registers for which I
> > > wrote a cascaded interrupt controller driver in 2022. This register
> > > group is instantiated multiple times in the SJA1110, which justified a
> > > reusable driver.
> > >
> > > Upstreaming it was blocked by the inability to instantiate it from the
> > > main DSA driver using backwards-compatible DT bindings.
> > >
> > > In any case, on the older generation SJA1105 (common driver with
> > > SJA1110), the GPIO and interrupt controller blocks are missing. There
> > > is an ACU block, but it handles just pinmux and pad configuration, and
> > > the DSA driver programs it directly rather than going through the
> > > pinmux subsystem.
> > >
> > > This highlights a key requirement I have from the API for
> > > instantiating sub-devices: that it is sufficiently flexible to split
> > > them out of the main device when that starts making sense (we identify
> > > a reusable block, or we need to configure it in the device tree, etc).
> > > Otherwise, chopping up the switch address space upfront is a huge
> > > overhead that may have no practical gains.
> >
> > I certainly understand the challenges.
> >
> > However, from my PoV, if you are instantiating one driver, even if it
> > does a bunch of different things which _could_ be split-up into all
> > sorts of far reaching subsystems, it's still one driver and therefore
> > does not meet the criteria for inclusion into MFD.
> >
> > I had to go and remind myself of your DT:
> >
> > ethernet-switch@0 {
> > compatible = "nxp,sja1110a";
> >
> > mdios {
> > mdio@0 {
> > compatible = "nxp,sja1110-base-t1-mdio";
> > };
> >
> > mdio@1 {
> > compatible = "nxp,sja1110-base-tx-mdio";
> > };
> > };
> > };
> >
> > To my untrained eye, this looks like two instances of a MDIO device.
> >
> > Are they truly different enough to be classified for "Multi"?
>
> Careful about terms, these are MDIO "buses" and not MDIO "devices"
> (children of those buses).
Noted. But then isn't it odd to see the bus mentioned in the compatible
string. Don't we usually only see this in the controller's compatibles?
> Let me reframe what I think you are saying.
>
> If the aesthetics of the dt-bindings of my SPI device were like this (1):
>
> spi {
> mfd@0 {
> ^ reg = <0>; // SPI chip select
> | #address-cells = <1>;
> | #size-cells = <1>;
> |
> | ethernet-switch@0 { // SWITCH region (0x000000 0x3ffffc) ^
> | reg = <0x000000 0x400000>; | DSA probes only here
> | }; v
> |
> | mdio@704000 { // 100BASE-T1 region (0x704000 0x704ffc)
> | reg = <0x704000 0x1000>;
> | }
> |
> Entire SPI | ethernet-pcs@705000 { // SGMII1 region (0x705000 0x705ffc)
> device address | reg = <0x705000 0x1000>;
> space | }
> (0x0-0x71FFFC), |
> up for grabs | ethernet-pcs@706000 { // SGMII2 region (0x706000 0x706ffc)
> by sub-devices | reg = <0x706000 0x1000>;
> | };
> |
> | ethernet-pcs@707000 { // SGMII3 region (0x707000 0x707ffc)
> | reg = <0x707000 0x1000>;
> | };
> |
> | ethernet-pcs@708000 { // SGMII4 region (0x708000 0x708ffc)
> | reg = <0x708000 0x1000>;
> | };
> |
> | mdio@709000 { // 100BASE-TX region (0x709000 0x709ffc)
> | reg = <0x709000 0x1000>;
> | };
> v };
> };
>
> then you wouldn't have had any issue about this not being MFD, correct?
Right. This is more in-line with what I would expect to see.
> I think this is an important base fact to establish.
> It looks fairly similar to Colin Foster's bindings for VSC7512, save for
> the fact that the sub-devices are slightly more varied (which is inconsequential,
> as Andrew seems to agree).
>
> However, the same physical reality is being described in these _actual_
> dt-bindings (2):
>
> spi {
> ethernet-switch@0 { // DSA probes here
> ^ reg = <0>; // SPI chip select
> |
> | // Legacy sub-devices (presently registered by DSA driver),
> | // already established dt-binding, proposal is to keep bindings unchanged,
> | // but to register using MFD
> | mdios {
> | mdio@0 { // 100BASE-T1 region (0x704000 0x704ffc)
> | compatible = "nxp,sja1110-base-t1-mdio";
> | };
> |
> | mdio@1 { // 100BASE-TX region (0x709000 0x709ffc)
> | compatible = "nxp,sja1110-base-tx-mdio";
> | };
> | };
> |
> | regs { // Proposed binding addition, anything here is MFD child ^
> | #address-cells = <1>; |
> Entire SPI | #size-cells = <1>; |
> device address | |
> space | ethernet-pcs@705000 { // SGMII1 region (0x705000 0x705ffc) |
> (0x0-0x71FFFC) | reg = <0x705000 0x1000>; |
> owned by DSA | } |
> driver | |
> | ethernet-pcs@706000 { // SGMII2 region (0x706000 0x706ffc) | Entire SPI
> | reg = <0x706000 0x1000>; | device address
> | }; | space again
> | | (0x0-0x71FFFC)
> | ethernet-pcs@707000 { // SGMII3 region (0x707000 0x707ffc) | up for grabs
> | reg = <0x707000 0x1000>; | by sub-devices
> | }; |
> | |
> | ethernet-pcs@708000 { // SGMII4 region (0x708000 0x708ffc) |
> | reg = <0x708000 0x1000>; |
> | }; |
> | }; v
> v };
> };
>
> Your issue is that, when looking at these real dt-bindings,
> superficially the MDIO buses don't "look" like MFD.
>
> To which, yes, I have no objection, they don't look like MFD because
> they were written as additions on top of the DSA schema structure, not
> according to the MFD schema.
>
> In reality it doesn't matter much where the MDIO bus nodes are (they
> could have been under "regs" as well, or under "mfd@0"), because DSA
> ports get references to their children using phandles. It's just that
> they are _already_ where they are, and moving them would be an avoidable
> breaking change.
Right. I think this is highly related to one of my previous comments.
I can't find it right now, but it was to the tune of; if a single driver
provides lots of functionality that _could_ be split-up, spread across
multiple different subsystems which all enumerate as completely
separate device-drivers, but isn't, then it still shouldn't meet the
criteria.
> > > > > I need to remind you that my purpose here is not to add drivers in
> > > > > breadth for all SJA1110 sub-devices now.
> > > >
> > > > You'll see from my discussions with Colin, sub-drivers (if they are
> > > > to be used for MFD justification (point 3 above), then they must be
> > > > added as part of the first submission. Perhaps this isn't an MFD,
> > > > "yet"?
> > > >
> > > > [...]
> > >
> > > IMHO, the concept of being or not being MFD "yet" is silly. Based on
> > > the register map, you are, or are not.
> >
> > Perhaps I didn't explain this very well. What I'm alluding to here is
> > that perhaps this a collection of different devices that may well fit
> > comfortably with the remit of MFD. However, I haven't seen any
> > compelling evidence of that in this current submission.
> >
> > As an example, when contributors submit an MFD core driver with only one
> > device, let's say a few Regulators but promise that the device is
> > actually capable of operating as a Watchdog, a Real-Time Clock and a
> > Power-on Key, only they haven't authored the drivers for those yet. The
> > driver get NACKed until at least one other piece of functionality is
> > available. Else the "Multi" box isn't ticked and therefore does not
> > qualify for inclusion.
>
> Exactly. DSA drivers get more developed with new each new hardware
> generation, and you wouldn't want to see an MFD driver + its bindings
> "just in case" new sub-devices will appear, when currently the DSA
> switch is the only component supported by Linux (and maybe its internal
> MDIO bus).
If only one device is currently supported, then again, it doesn't meet
the criteria. I've had a bunch of developers attempt to upstream
support for a single device and insist that more sub-devices are coming
which would make it an MFD, but that's not how it works. Devices must
meet the criteria _now_. So I usually ask them go take the time to get
at least one more device ready before attempting to upstream.
> You provided exactly the reason why the dt-bindings of SJA1110 look like (2),
> yet you dislike they don't look like (1) in order to fit the narrow
> understanding of how the MFD API should be used.
My requests really aren't that narrow and this one is pretty critical:
* Must support more than one different device.
> > The "yet" part was alluding to the fact that this may be the case here.
>
> Yes, so in my understanding it's MFD if it uses mfd_add_devices() and
> it's not MFD if it doesn't.
It's a little more complicated than that.
We also support "simple-mfd", "syscon" and of_platform_populate().
Is there any reason not to put mdio_cbt and mdio_cbt1 resources into the
device tree or make them available somewhere else (e.g.
driver.of_match_table.data) and use of_platform_populate() instead of
mfd_add_devices() (I can't remember if we've suggested that before or
not).
> > > > > The SGMII blocks are highly reusable IPs licensed from Synopsys,
> > > > > and Linux already has DT bindings and a corresponding platform
> > > > > driver for the case where their registers are viewed using MMIO.
> > > >
> > > > This is a good reason for dividing them up into subordinate platform
> > > > devices. However, it is not a good use-case of MFD. In it's
> > > > current guise, your best bet is to use the platform_* API directly.
> > > >
> > > > This is a well trodden path and it not challenging:
> > > >
> > > > % git grep platform_device_add -- arch drivers sound | wc -l 398
> > > >
> > > > [...]
> > > >
> > > > > In my opinion I do not need to add handling for any other
> > > > > sub-device, for the support to be more "cross-system" like for
> > > > > Ocelot. What is here is enough for you to decide if this is
> > > > > adequate for MFD or not.
> > > >
> > > > Currently ... it's not.
> > > >
> > > > [...]
> > > >
> > > > Hopefully that helps to clarify my expectations a little.
> > > >
> > > > TL;DR, this looks like a good candidate for direct platform_* usage.
> > >
> > > I do have a local branch with platform devices created manually, and
> > > yet, I considered the mfd_add_devices() form looked cleaner when
> > > submitting.
> > >
> > > I expect the desire to split up reusable register regions into
> > > platform sub-devices to pop up again, so the logic should be available
> > > as library code at some level (possibly DSA).
> > >
> > > Unless you have something against the idea, I'm thinking a good name
> > > for this library code would be "nmfd", for "Not MFD". It is like MFD,
> > > except: - the parent can simultaneously handle the main function of
> > > the device while delegating other regions to sub-devices - the
> > > sub-devices can all have drivers in the same subsystem (debatable
> > > whether MFD follows this - just to avoid discussions) - their OF nodes
> > > don't have to be direct children of the parent.
> >
> > Well, we already have Simple MFD which works for some basic use-cases.
> >
> > When I've thought about replacing the existing occurrences of the MFD
> > API being used outside of drivers/mfd, I have often thought of a
> > platform_add_device_simple() call which I believe would do what most
> > people of these use-cases actually want.
>
> Would this platform_add_device_simple() share or duplicate code with
> mfd_add_devices()? Why not just liberalize mfd_add_devices() (the
> simplest solution)?
This is not an option, for the aforementioned reasons. In fact, my plan
is to do the exact opposite.
Right, I think we've discussed this enough. I've made a decision.
If the of_platform_populate() solution doesn't work for you for some
reason (although I think it should), given the points you've put
forward, I would be content for you to house the child device
registration (via mfd_add_devices) in drivers/mfd if you so wish.
Although I still don't think modifying the core to ignore bespoke empty
"container" nodes is acceptable. It looks like this was merged without
a proper DT review. I'm surprised that this was accepted.
--
Lee Jones [李琼斯]
On Thu, Jan 15, 2026 at 04:14:07PM +0000, Lee Jones wrote:
> > > My plan, when and if I manage to find a few spare cycles, is to remove
> > > MFD use from outside drivers/mfd. That's been my rule since forever.
> > > Having this in place ensures that the other rules are kept and (mild)
> > > chaos doesn't ensue. The MFD API is trivial to abuse. You wouldn't
> > > believe some of things I've seen over the years. Each value I have is
> > > there for a historical reason.
> >
> > If you're also of the opinion that MFD is a Linux-specific
> > implementation detail and a figment of our imagination as developers,
> > then I certainly don't understand why Documentation/devicetree/bindings/mfd/
> > exists for this separate device class that is MFD, and why you don't
> > liberalize access to mfd_add_devices() instead.
>
> The first point is a good one. It mostly exists for historical
> reasons and for want of a better place to locate the documentation.
>
> I've explained why liberalising the mfd_*() API is a bad idea. "Clever"
> developers like to do some pretty crazy stuff involving the use of
> multiple device registration APIs simultaneously. I've also seen some
> bonkers methods of dynamically populating MFD cells [*ahem* Patch 8
> =;-)] and various other things. Keeping the API in-house allows me to
> keep things simple, easily readable and maintainable.
The only thing that's crazy to me is how the MFD documentation (+ my
intuition as engineer to fill in the gaps where the documentation was
lacking, aka in a lot of places) could be so far off from what you lay
out as your maintainer expectations here.
> > > I had to go and remind myself of your DT:
> > >
> > > ethernet-switch@0 {
> > > compatible = "nxp,sja1110a";
> > >
> > > mdios {
> > > mdio@0 {
> > > compatible = "nxp,sja1110-base-t1-mdio";
> > > };
> > >
> > > mdio@1 {
> > > compatible = "nxp,sja1110-base-tx-mdio";
> > > };
> > > };
> > > };
> > >
> > > To my untrained eye, this looks like two instances of a MDIO device.
> > >
> > > Are they truly different enough to be classified for "Multi"?
> >
> > Careful about terms, these are MDIO "buses" and not MDIO "devices"
> > (children of those buses).
>
> Noted. But then isn't it odd to see the bus mentioned in the compatible
> string. Don't we usually only see this in the controller's compatibles?
???
bus == controller.
The "nxp,sja1110-base-t1-mdio" and "nxp,sja1110-base-tx-mdio" are MDIO
buses/controllers following the Documentation/devicetree/bindings/net/mdio.yaml
schema.
There are plenty of other devices which have "$ref: mdio.yaml#" and
which have "mdio" in their compatible string: "ti,davinci_mdio",
"qcom,ipq8064-mdio"... This is the same thing.
The "MDIO bus" / "MDIO device" terminology distinction is no different
than "SPI bus" / "SPI device", if that helps you better understand why I
said "buses, not devices".
> > Let me reframe what I think you are saying.
> >
> > If the aesthetics of the dt-bindings of my SPI device were like this (1):
> >
> > (...)
> >
> > then you wouldn't have had any issue about this not being MFD, correct?
>
> Right. This is more in-line with what I would expect to see.
>
> > I think this is an important base fact to establish.
> > It looks fairly similar to Colin Foster's bindings for VSC7512, save for
> > the fact that the sub-devices are slightly more varied (which is inconsequential,
> > as Andrew seems to agree).
> >
> > However, the same physical reality is being described in these _actual_
> > dt-bindings (2):
> >
> > (...)
> >
> > Your issue is that, when looking at these real dt-bindings,
> > superficially the MDIO buses don't "look" like MFD.
> >
> > To which, yes, I have no objection, they don't look like MFD because
> > they were written as additions on top of the DSA schema structure, not
> > according to the MFD schema.
> >
> > In reality it doesn't matter much where the MDIO bus nodes are (they
> > could have been under "regs" as well, or under "mfd@0"), because DSA
> > ports get references to their children using phandles. It's just that
> > they are _already_ where they are, and moving them would be an avoidable
> > breaking change.
>
> Right. I think this is highly related to one of my previous comments.
>
> I can't find it right now, but it was to the tune of; if a single driver
> provides lots of functionality that _could_ be split-up, spread across
> multiple different subsystems which all enumerate as completely
> separate device-drivers, but isn't, then it still shouldn't meet the
> criteria.
Any arbitrary set of distinct functions can be grouped into a new
monolithic driver. Are you saying that grouping them together is fine,
but never split them back up, at least not using MFD? What's the logic?
> > Exactly. DSA drivers get more developed with new each new hardware
> > generation, and you wouldn't want to see an MFD driver + its bindings
> > "just in case" new sub-devices will appear, when currently the DSA
> > switch is the only component supported by Linux (and maybe its internal
> > MDIO bus).
>
> If only one device is currently supported, then again, it doesn't meet
> the criteria. I've had a bunch of developers attempt to upstream
> support for a single device and insist that more sub-devices are coming
> which would make it an MFD, but that's not how it works. Devices must
> meet the criteria _now_. So I usually ask them go take the time to get
> at least one more device ready before attempting to upstream.
sja1105 is a multi-generational DSA driver. Gen 1 SJA1105E/T has 0
sub-devices, Gen 2 SJA1105R/S have 1 sub-device (XPCS) and Gen3 SJA1110
have 5+ sub-devices.
The driver was written for Gen 1, then was expanded for the later
generations as the silicon was released (multiple years in between these
events).
You are effectively saying:
- MAX77540 wouldn't have been accepted as MFD on its own, it was
effectively carried in by MAX77541 support.
- A driver that doesn't have sufficiently varied subfunctions doesn't
qualify as MFD.
- A monolithic driver whose subfunctions can be split up doesn't meet
the MFD criteria.
So in your rule system, a multi-generational driver which evolves into
having multiple sub-devices has no chance of ever using MFD, unless it
is written after the evolution has stopped, and the old generations
become obsolete.
Unless you're of the opinion that it's my fault for not predicting the
future and waiting until the SJA1110 came out in order to write an MFD
driver, I suggest you could reconsider your rules so that they're less
focused on your comfort as maintainer, at the expense of fairness and
coherency for other developers.
> Is there any reason not to put mdio_cbt and mdio_cbt1 resources into the
> device tree
That ship has sailed and there are device trees in circulation with
existing mdio_cbtx/mdio_cbt1 bindings.
> or make them available somewhere else (e.g. driver.of_match_table.data)
> and use of_platform_populate() instead of mfd_add_devices() (I can't
> remember if we've suggested that before or not).
I never got of_platform_populate() to work for a pretty fundamental
reason, so I don't have enough information to know what you're on about
with making the mdio_cbtx/mdio_cbt1 resources available to it.
> Right, I think we've discussed this enough. I've made a decision.
>
> If the of_platform_populate() solution doesn't work for you for some
> reason (although I think it should),
Quote from the discussion on patch 8:
I did already explore of_platform_populate() on this thread which asked
for advice (to which you were also copied):
https://lore.kernel.org/lkml/20221222134844.lbzyx5hz7z5n763n@skbuf/
It looks like of_platform_populate() would be an alternative option for
this task, but that doesn't live up to the task either. It will assume
that the addresses of the SoC children are in the CPU's address space
(IORESOURCE_MEM), and attempt to translate them. It simply doesn't have
the concept of IORESOURCE_REG. The MFD drivers which call
of_platform_populate() (simple-mfd-i2c.c) simply don't have unit
addresses for their children, and this is why address translation isn't
a problem for them.
In fact, this seems to be a rather large limitation of include/linux/of_address.h.
Even something as simple as of_address_count() will end up trying to
translate the address into the CPU memory space, so not even open-coding
the resource creation in the SoC driver is as simple as it appears.
Is there a better way than completely open-coding the parsing of the OF
addresses when turning them into IORESOURCE_REG resources (or open-coding
mfd_cells for each child)? Would there be a desire in creating a generic
set of helpers which create platform devices with IORESOURCE_REG resources,
based solely on OF addresses of children? What would be the correct
scope for these helpers?
> given the points you've put forward, I would be content for you to
> house the child device registration (via mfd_add_devices) in
> drivers/mfd if you so wish.
Thanks! But I don't know how this helps me :)
Since your offer involves changing dt-bindings in order to separate the
MFD parent from the DSA switch (currently the DSA driver probes on the
spi_device, clashing with the MFD parent which wants the same thing), I
will have to pass.
Not because I insist on being difficult, but because I know that when I
change dt-bindings, the old ones don't just disappear and will continue
to have to be supported, likely through a separate code path that would
also increase code complexity.
> Although I still don't think modifying the core to ignore bespoke empty
> "container" nodes is acceptable. It looks like this was merged without
> a proper DT review. I'm surprised that this was accepted.
There was a debate when this was accepted, but we didn't come up with
anything better to fulfill the following constraints:
- As per mdio.yaml, the $nodename has to follow the pattern:
'^mdio(-(bus|external))?(@.+|-([0-9]+))?$'
- There are two MDIO buses. So we have to choose the variant with a
unit-address (both MDIO buses are for internal PHYs, so we can't call
one "mdio" and the other "mdio-external").
- Nodes with a unit address can't be hierarchical neighbours with nodes
with no unit address (concretely: "ethernet-ports" from
Documentation/devicetree/bindings/net/ethernet-switch.yaml, the main
schema that the DSA switch conforms to). This is because their parent
either has #address-cells = <0>, or #address-cells = <1>. It can't
simultaneously have two values.
Simply put, there is no good place to attach child nodes with unit
addresses to a DT node following the DSA (or the more general
ethernet-switch) schema. The "mdios" container node serves exactly that
adaptation purpose.
I am genuinely curious how you would have handled this better, so that I
also know better next time when I'm in a similar situation.
Especially since "mdios" is not the only container node with this issue.
The "regs" node proposed in patch 14 serves exactly the same purpose
(#address-cells adaptation), and needs the exact same ".parent_of_node = regs_node"
workaround in the mfd_cell.
On Thu, 15 Jan 2026, Vladimir Oltean wrote:
> On Thu, Jan 15, 2026 at 04:14:07PM +0000, Lee Jones wrote:
> > > > My plan, when and if I manage to find a few spare cycles, is to remove
> > > > MFD use from outside drivers/mfd. That's been my rule since forever.
> > > > Having this in place ensures that the other rules are kept and (mild)
> > > > chaos doesn't ensue. The MFD API is trivial to abuse. You wouldn't
> > > > believe some of things I've seen over the years. Each value I have is
> > > > there for a historical reason.
> > >
> > > If you're also of the opinion that MFD is a Linux-specific
> > > implementation detail and a figment of our imagination as developers,
> > > then I certainly don't understand why Documentation/devicetree/bindings/mfd/
> > > exists for this separate device class that is MFD, and why you don't
> > > liberalize access to mfd_add_devices() instead.
> >
> > The first point is a good one. It mostly exists for historical
> > reasons and for want of a better place to locate the documentation.
> >
> > I've explained why liberalising the mfd_*() API is a bad idea. "Clever"
> > developers like to do some pretty crazy stuff involving the use of
> > multiple device registration APIs simultaneously. I've also seen some
> > bonkers methods of dynamically populating MFD cells [*ahem* Patch 8
> > =;-)] and various other things. Keeping the API in-house allows me to
> > keep things simple, easily readable and maintainable.
>
> The only thing that's crazy to me is how the MFD documentation (+ my
> intuition as engineer to fill in the gaps where the documentation was
> lacking, aka in a lot of places) could be so far off from what you lay
> out as your maintainer expectations here.
MFD has documentation? =;-)
/me `find . | grep -i mfd`s
Okay, the only "MFD documentation" I can find is:
Documentation/devicetree/bindings/mfd/mfd.txt
The first paragraph reflects the point I've been trying to make:
"These devices comprise a nexus for HETEROGENEOUS hardware blocks
containing more than one non-unique yet VARYING HARDWARE FUNCTIONALITY.
2 MDIO controllers are homogeneous to each other and are not varying.
How is the documentation and what I say "so far off"?
> > > > I had to go and remind myself of your DT:
> > > >
> > > > ethernet-switch@0 {
> > > > compatible = "nxp,sja1110a";
> > > >
> > > > mdios {
> > > > mdio@0 {
> > > > compatible = "nxp,sja1110-base-t1-mdio";
> > > > };
> > > >
> > > > mdio@1 {
> > > > compatible = "nxp,sja1110-base-tx-mdio";
> > > > };
> > > > };
> > > > };
> > > >
> > > > To my untrained eye, this looks like two instances of a MDIO device.
> > > >
> > > > Are they truly different enough to be classified for "Multi"?
> > >
> > > Careful about terms, these are MDIO "buses" and not MDIO "devices"
> > > (children of those buses).
> >
> > Noted. But then isn't it odd to see the bus mentioned in the compatible
> > string. Don't we usually only see this in the controller's compatibles?
>
> ???
> bus == controller.
> The "nxp,sja1110-base-t1-mdio" and "nxp,sja1110-base-tx-mdio" are MDIO
> buses/controllers following the Documentation/devicetree/bindings/net/mdio.yaml
> schema.
> There are plenty of other devices which have "$ref: mdio.yaml#" and
> which have "mdio" in their compatible string: "ti,davinci_mdio",
> "qcom,ipq8064-mdio"... This is the same thing.
>
> The "MDIO bus" / "MDIO device" terminology distinction is no different
> than "SPI bus" / "SPI device", if that helps you better understand why I
> said "buses, not devices".
Okay, so these are the MDIO bus controllers - that's clear now, thank you.
I was confused by the t1 and tx parts. Are these different types of
MDIO controllers or are they the same, but vary only in support / role?
But again, if these are "both MDIO controllers", then they are _same_.
> > > Let me reframe what I think you are saying.
> > >
> > > If the aesthetics of the dt-bindings of my SPI device were like this (1):
> > >
> > > (...)
> > >
> > > then you wouldn't have had any issue about this not being MFD, correct?
> >
> > Right. This is more in-line with what I would expect to see.
> >
> > > I think this is an important base fact to establish.
> > > It looks fairly similar to Colin Foster's bindings for VSC7512, save for
> > > the fact that the sub-devices are slightly more varied (which is inconsequential,
> > > as Andrew seems to agree).
> > >
> > > However, the same physical reality is being described in these _actual_
> > > dt-bindings (2):
> > >
> > > (...)
> > >
> > > Your issue is that, when looking at these real dt-bindings,
> > > superficially the MDIO buses don't "look" like MFD.
> > >
> > > To which, yes, I have no objection, they don't look like MFD because
> > > they were written as additions on top of the DSA schema structure, not
> > > according to the MFD schema.
> > >
> > > In reality it doesn't matter much where the MDIO bus nodes are (they
> > > could have been under "regs" as well, or under "mfd@0"), because DSA
> > > ports get references to their children using phandles. It's just that
> > > they are _already_ where they are, and moving them would be an avoidable
> > > breaking change.
> >
> > Right. I think this is highly related to one of my previous comments.
> >
> > I can't find it right now, but it was to the tune of; if a single driver
> > provides lots of functionality that _could_ be split-up, spread across
> > multiple different subsystems which all enumerate as completely
> > separate device-drivers, but isn't, then it still shouldn't meet the
> > criteria.
>
> Any arbitrary set of distinct functions can be grouped into a new
> monolithic driver. Are you saying that grouping them together is fine,
> but never split them back up, at least not using MFD? What's the logic?
No, the opposite I think?
I'm saying that when they are grouped into a monolithic driver, they do
not match the criteria of an MFD, but if the _varying_ functionality was
split-up and probed individually, they would. Take this example:
# Bad
static struct mfd_cell cells[] = {
MFD_CELL_NAME("abc-monolithic")
};
# Bad
static struct mfd_cell cells[] = {
MFD_CELL_NAME("abc-function-a")
MFD_CELL_NAME("abc-function-a")
};
# Good
static struct mfd_cell cells[] = {
MFD_CELL_NAME("abc-function-a")
MFD_CELL_NAME("abc-function-b")
};
At the moment, from what I see in front of me, you are the middle one.
> > > Exactly. DSA drivers get more developed with new each new hardware
> > > generation, and you wouldn't want to see an MFD driver + its bindings
> > > "just in case" new sub-devices will appear, when currently the DSA
> > > switch is the only component supported by Linux (and maybe its internal
> > > MDIO bus).
> >
> > If only one device is currently supported, then again, it doesn't meet
> > the criteria. I've had a bunch of developers attempt to upstream
> > support for a single device and insist that more sub-devices are coming
> > which would make it an MFD, but that's not how it works. Devices must
> > meet the criteria _now_. So I usually ask them go take the time to get
> > at least one more device ready before attempting to upstream.
>
> sja1105 is a multi-generational DSA driver. Gen 1 SJA1105E/T has 0
> sub-devices, Gen 2 SJA1105R/S have 1 sub-device (XPCS) and Gen3 SJA1110
> have 5+ sub-devices.
>
> The driver was written for Gen 1, then was expanded for the later
> generations as the silicon was released (multiple years in between these
> events).
>
> You are effectively saying:
> - MAX77540 wouldn't have been accepted as MFD on its own, it was
> effectively carried in by MAX77541 support.
> - A driver that doesn't have sufficiently varied subfunctions doesn't
> qualify as MFD.
> - A monolithic driver whose subfunctions can be split up doesn't meet
> the MFD criteria.
If it "can", but isn't, then it doesn't, that's correct.
But if it _is_ split-up then it does.
> So in your rule system, a multi-generational driver which evolves into
> having multiple sub-devices has no chance of ever using MFD, unless it
> is written after the evolution has stopped, and the old generations
> become obsolete.
I'm really not. I'm saying that if the driver were to be spit-up, then
it _would_ match the criteria and it would be free to use MFD to
register those split-up sub-devices.
> Unless you're of the opinion that it's my fault for not predicting the
> future and waiting until the SJA1110 came out in order to write an MFD
> driver, I suggest you could reconsider your rules so that they're less
> focused on your comfort as maintainer, at the expense of fairness and
> coherency for other developers.
This isn't what I've said at all.
What I have said is that even though you've split this up, you have only
split it up into 2 homogeneous devices / controllers, which still does
not qualify.
If you have plans to split out another varying function, other than an
MDIO controller, then do so and you can then easily qualify.
> > Is there any reason not to put mdio_cbt and mdio_cbt1 resources into the
> > device tree
>
> That ship has sailed and there are device trees in circulation with
> existing mdio_cbtx/mdio_cbt1 bindings.
>
> > or make them available somewhere else (e.g. driver.of_match_table.data)
> > and use of_platform_populate() instead of mfd_add_devices() (I can't
> > remember if we've suggested that before or not).
>
> I never got of_platform_populate() to work for a pretty fundamental
> reason, so I don't have enough information to know what you're on about
> with making the mdio_cbtx/mdio_cbt1 resources available to it.
>
> > Right, I think we've discussed this enough. I've made a decision.
> >
> > If the of_platform_populate() solution doesn't work for you for some
> > reason (although I think it should),
>
> Quote from the discussion on patch 8:
>
> I did already explore of_platform_populate() on this thread which asked
> for advice (to which you were also copied):
> https://lore.kernel.org/lkml/20221222134844.lbzyx5hz7z5n763n@skbuf/
>
> It looks like of_platform_populate() would be an alternative option for
> this task, but that doesn't live up to the task either. It will assume
> that the addresses of the SoC children are in the CPU's address space
> (IORESOURCE_MEM), and attempt to translate them. It simply doesn't have
> the concept of IORESOURCE_REG. The MFD drivers which call
> of_platform_populate() (simple-mfd-i2c.c) simply don't have unit
> addresses for their children, and this is why address translation isn't
> a problem for them.
>
> In fact, this seems to be a rather large limitation of include/linux/of_address.h.
> Even something as simple as of_address_count() will end up trying to
> translate the address into the CPU memory space, so not even open-coding
> the resource creation in the SoC driver is as simple as it appears.
>
> Is there a better way than completely open-coding the parsing of the OF
> addresses when turning them into IORESOURCE_REG resources (or open-coding
> mfd_cells for each child)? Would there be a desire in creating a generic
> set of helpers which create platform devices with IORESOURCE_REG resources,
> based solely on OF addresses of children? What would be the correct
> scope for these helpers?
Does this all boil down that pesky empty 'mdio' "container"?
Or even if it doesn't: if what you have is a truly valid DT, then why
not adapt drivers/of/platform.c to cater for your use-case? Then you
could take your pick from whatever works better for you out of
of_platform_populate(), 'simple-bus' or even 'simple-mfd'.
> > given the points you've put forward, I would be content for you to
> > house the child device registration (via mfd_add_devices) in
> > drivers/mfd if you so wish.
>
> Thanks! But I don't know how this helps me :)
>
> Since your offer involves changing dt-bindings in order to separate the
> MFD parent from the DSA switch (currently the DSA driver probes on the
> spi_device, clashing with the MFD parent which wants the same thing), I
> will have to pass.
I haven't taken a look at the DT bindings in close enough detail to
provide a specific solution, but _perhaps_ it would be possible to match
the MFD driver to the existing compatible, then use the MFD driver to
register the current DSA driver.
However, after this most recent exchange, I am even less confident that
using the MFD API to register only 2 MDIO controllers is the right thing
to do.
> Not because I insist on being difficult, but because I know that when I
> change dt-bindings, the old ones don't just disappear and will continue
> to have to be supported, likely through a separate code path that would
> also increase code complexity.
Right, they have to be backwardly compatible, I get that.
> > Although I still don't think modifying the core to ignore bespoke empty
> > "container" nodes is acceptable. It looks like this was merged without
> > a proper DT review. I'm surprised that this was accepted.
>
> There was a debate when this was accepted, but we didn't come up with
> anything better to fulfill the following constraints:
> - As per mdio.yaml, the $nodename has to follow the pattern:
> '^mdio(-(bus|external))?(@.+|-([0-9]+))?$'
> - There are two MDIO buses. So we have to choose the variant with a
> unit-address (both MDIO buses are for internal PHYs, so we can't call
> one "mdio" and the other "mdio-external").
> - Nodes with a unit address can't be hierarchical neighbours with nodes
> with no unit address (concretely: "ethernet-ports" from
> Documentation/devicetree/bindings/net/ethernet-switch.yaml, the main
> schema that the DSA switch conforms to). This is because their parent
> either has #address-cells = <0>, or #address-cells = <1>. It can't
> simultaneously have two values.
>
> Simply put, there is no good place to attach child nodes with unit
> addresses to a DT node following the DSA (or the more general
> ethernet-switch) schema. The "mdios" container node serves exactly that
> adaptation purpose.
>
> I am genuinely curious how you would have handled this better, so that I
> also know better next time when I'm in a similar situation.
>
> Especially since "mdios" is not the only container node with this issue.
> The "regs" node proposed in patch 14 serves exactly the same purpose
> (#address-cells adaptation), and needs the exact same ".parent_of_node = regs_node"
> workaround in the mfd_cell.
Please correct me if I'm wrong, but from what I have gathered, all
you're trying to do here is probe a couple of child devices
(controllers, whatever) and you've chosen to use MFD for this purpose
because the other, more generic machinery that would normally _just
work_ for simple scenarios like this, do not because you are attempting
to support a non-standard DT. Or at least one that isn't supported.
With that in mind, some suggestions going forward in order of preference:
- Adapt the current auto-registering infrastructure to support your DT layout
- of_platform_populate(), simple-bus, simple-mfd, etc
- Use fundamental / generic / flexible APIs that do not have specific rules
- platform_*()
- Move the mfd_device_add() usage into drivers/mfd
- Although after this exchange, this is now my least preferred option
Hope that helps. Good luck with however you decide to proceed.
--
Lee Jones [李琼斯]
On Fri, Jan 16, 2026 at 08:40:21AM +0000, Lee Jones wrote:
> On Thu, 15 Jan 2026, Vladimir Oltean wrote:
>
> > On Thu, Jan 15, 2026 at 04:14:07PM +0000, Lee Jones wrote:
> > > > > My plan, when and if I manage to find a few spare cycles, is to remove
> > > > > MFD use from outside drivers/mfd. That's been my rule since forever.
> > > > > Having this in place ensures that the other rules are kept and (mild)
> > > > > chaos doesn't ensue. The MFD API is trivial to abuse. You wouldn't
> > > > > believe some of things I've seen over the years. Each value I have is
> > > > > there for a historical reason.
> > > >
> > > > If you're also of the opinion that MFD is a Linux-specific
> > > > implementation detail and a figment of our imagination as developers,
> > > > then I certainly don't understand why Documentation/devicetree/bindings/mfd/
> > > > exists for this separate device class that is MFD, and why you don't
> > > > liberalize access to mfd_add_devices() instead.
> > >
> > > The first point is a good one. It mostly exists for historical
> > > reasons and for want of a better place to locate the documentation.
> > >
> > > I've explained why liberalising the mfd_*() API is a bad idea. "Clever"
> > > developers like to do some pretty crazy stuff involving the use of
> > > multiple device registration APIs simultaneously. I've also seen some
> > > bonkers methods of dynamically populating MFD cells [*ahem* Patch 8
> > > =;-)] and various other things. Keeping the API in-house allows me to
> > > keep things simple, easily readable and maintainable.
> >
> > The only thing that's crazy to me is how the MFD documentation (+ my
> > intuition as engineer to fill in the gaps where the documentation was
> > lacking, aka in a lot of places) could be so far off from what you lay
> > out as your maintainer expectations here.
>
> MFD has documentation? =;-)
>
> /me `find . | grep -i mfd`s
>
> Okay, the only "MFD documentation" I can find is:
>
> Documentation/devicetree/bindings/mfd/mfd.txt
Exactly my point!
> The first paragraph reflects the point I've been trying to make:
>
> "These devices comprise a nexus for HETEROGENEOUS hardware blocks
> containing more than one non-unique yet VARYING HARDWARE FUNCTIONALITY.
>
> 2 MDIO controllers are homogeneous to each other and are not varying.
I get the impression you didn't look at patch 14, where I also added the
ethernet-pcs blocks to MFD children.
> How is the documentation and what I say "so far off"?
Well, it's far off because I got the genuine impression that I'm making
legitimate use of the MFD API.
> Okay, so these are the MDIO bus controllers - that's clear now, thank you.
>
> I was confused by the t1 and tx parts. Are these different types of
> MDIO controllers or are they the same, but vary only in support / role?
>
> But again, if these are "both MDIO controllers", then they are _same_.
Their register map (i.e. way of accessing the underlying MDIO devices,
aka internal PHYs) is different. They have different drivers, one is
added by patch 3 and the other by patch 4.
Here is the link to the entire set:
https://lore.kernel.org/netdev/20251118190530.580267-1-vladimir.oltean@nxp.com/
> > > > Let me reframe what I think you are saying.
> > > >
> > > > If the aesthetics of the dt-bindings of my SPI device were like this (1):
> > > >
> > > > (...)
> > > >
> > > > then you wouldn't have had any issue about this not being MFD, correct?
> > >
> > > Right. This is more in-line with what I would expect to see.
> > >
> > > > I think this is an important base fact to establish.
> > > > It looks fairly similar to Colin Foster's bindings for VSC7512, save for
> > > > the fact that the sub-devices are slightly more varied (which is inconsequential,
> > > > as Andrew seems to agree).
> > > >
> > > > However, the same physical reality is being described in these _actual_
> > > > dt-bindings (2):
> > > >
> > > > (...)
> > > >
> > > > Your issue is that, when looking at these real dt-bindings,
> > > > superficially the MDIO buses don't "look" like MFD.
> > > >
> > > > To which, yes, I have no objection, they don't look like MFD because
> > > > they were written as additions on top of the DSA schema structure, not
> > > > according to the MFD schema.
> > > >
> > > > In reality it doesn't matter much where the MDIO bus nodes are (they
> > > > could have been under "regs" as well, or under "mfd@0"), because DSA
> > > > ports get references to their children using phandles. It's just that
> > > > they are _already_ where they are, and moving them would be an avoidable
> > > > breaking change.
> > >
> > > Right. I think this is highly related to one of my previous comments.
> > >
> > > I can't find it right now, but it was to the tune of; if a single driver
> > > provides lots of functionality that _could_ be split-up, spread across
> > > multiple different subsystems which all enumerate as completely
> > > separate device-drivers, but isn't, then it still shouldn't meet the
> > > criteria.
> >
> > Any arbitrary set of distinct functions can be grouped into a new
> > monolithic driver. Are you saying that grouping them together is fine,
> > but never split them back up, at least not using MFD? What's the logic?
>
> No, the opposite I think?
>
> I'm saying that when they are grouped into a monolithic driver, they do
> not match the criteria of an MFD, but if the _varying_ functionality was
> split-up and probed individually, they would. Take this example:
>
> # Bad
> static struct mfd_cell cells[] = {
> MFD_CELL_NAME("abc-monolithic")
> };
>
> # Bad
> static struct mfd_cell cells[] = {
> MFD_CELL_NAME("abc-function-a")
> MFD_CELL_NAME("abc-function-a")
> };
>
> # Good
> static struct mfd_cell cells[] = {
> MFD_CELL_NAME("abc-function-a")
> MFD_CELL_NAME("abc-function-b")
> };
>
> At the moment, from what I see in front of me, you are the middle one.
I think you are missing patch 14.
Although for SJA1105R/S, I am indeed in the middle position (it has to
do with the multi-generational aspect I was telling you about).
> > > > Exactly. DSA drivers get more developed with new each new hardware
> > > > generation, and you wouldn't want to see an MFD driver + its bindings
> > > > "just in case" new sub-devices will appear, when currently the DSA
> > > > switch is the only component supported by Linux (and maybe its internal
> > > > MDIO bus).
> > >
> > > If only one device is currently supported, then again, it doesn't meet
> > > the criteria. I've had a bunch of developers attempt to upstream
> > > support for a single device and insist that more sub-devices are coming
> > > which would make it an MFD, but that's not how it works. Devices must
> > > meet the criteria _now_. So I usually ask them go take the time to get
> > > at least one more device ready before attempting to upstream.
> >
> > sja1105 is a multi-generational DSA driver. Gen 1 SJA1105E/T has 0
> > sub-devices, Gen 2 SJA1105R/S have 1 sub-device (XPCS) and Gen3 SJA1110
> > have 5+ sub-devices.
> >
> > The driver was written for Gen 1, then was expanded for the later
> > generations as the silicon was released (multiple years in between these
> > events).
> >
> > You are effectively saying:
> > - MAX77540 wouldn't have been accepted as MFD on its own, it was
> > effectively carried in by MAX77541 support.
> > - A driver that doesn't have sufficiently varied subfunctions doesn't
> > qualify as MFD.
> > - A monolithic driver whose subfunctions can be split up doesn't meet
> > the MFD criteria.
>
> If it "can", but isn't, then it doesn't, that's correct.
>
> But if it _is_ split-up then it does.
>
> > So in your rule system, a multi-generational driver which evolves into
> > having multiple sub-devices has no chance of ever using MFD, unless it
> > is written after the evolution has stopped, and the old generations
> > become obsolete.
>
> I'm really not. I'm saying that if the driver were to be spit-up, then
> it _would_ match the criteria and it would be free to use MFD to
> register those split-up sub-devices.
I don't know what you meant to say, but I quote what you actually said,
and how I interpreted it:
"if a single driver provides lots of functionality that _could_ be
split-up, (...), but isn't [ split up ], then it still shouldn't meet
the criteria [ for using the MFD API ]."
>
> > Unless you're of the opinion that it's my fault for not predicting the
> > future and waiting until the SJA1110 came out in order to write an MFD
> > driver, I suggest you could reconsider your rules so that they're less
> > focused on your comfort as maintainer, at the expense of fairness and
> > coherency for other developers.
>
> This isn't what I've said at all.
>
> What I have said is that even though you've split this up, you have only
> split it up into 2 homogeneous devices / controllers, which still does
> not qualify.
>
> If you have plans to split out another varying function, other than an
> MDIO controller, then do so and you can then easily qualify.
Ok, so we're getting close, you just need to take a look at patch 14.
> > > Is there any reason not to put mdio_cbt and mdio_cbt1 resources into the
> > > device tree
> >
> > That ship has sailed and there are device trees in circulation with
> > existing mdio_cbtx/mdio_cbt1 bindings.
> >
> > > or make them available somewhere else (e.g. driver.of_match_table.data)
> > > and use of_platform_populate() instead of mfd_add_devices() (I can't
> > > remember if we've suggested that before or not).
> >
> > I never got of_platform_populate() to work for a pretty fundamental
> > reason, so I don't have enough information to know what you're on about
> > with making the mdio_cbtx/mdio_cbt1 resources available to it.
> >
> > > Right, I think we've discussed this enough. I've made a decision.
> > >
> > > If the of_platform_populate() solution doesn't work for you for some
> > > reason (although I think it should),
> >
> > Quote from the discussion on patch 8:
> >
> > I did already explore of_platform_populate() on this thread which asked
> > for advice (to which you were also copied):
> > https://lore.kernel.org/lkml/20221222134844.lbzyx5hz7z5n763n@skbuf/
> >
> > It looks like of_platform_populate() would be an alternative option for
> > this task, but that doesn't live up to the task either. It will assume
> > that the addresses of the SoC children are in the CPU's address space
> > (IORESOURCE_MEM), and attempt to translate them. It simply doesn't have
> > the concept of IORESOURCE_REG. The MFD drivers which call
> > of_platform_populate() (simple-mfd-i2c.c) simply don't have unit
> > addresses for their children, and this is why address translation isn't
> > a problem for them.
> >
> > In fact, this seems to be a rather large limitation of include/linux/of_address.h.
> > Even something as simple as of_address_count() will end up trying to
> > translate the address into the CPU memory space, so not even open-coding
> > the resource creation in the SoC driver is as simple as it appears.
> >
> > Is there a better way than completely open-coding the parsing of the OF
> > addresses when turning them into IORESOURCE_REG resources (or open-coding
> > mfd_cells for each child)? Would there be a desire in creating a generic
> > set of helpers which create platform devices with IORESOURCE_REG resources,
> > based solely on OF addresses of children? What would be the correct
> > scope for these helpers?
>
> Does this all boil down that pesky empty 'mdio' "container"?
Why do you keep calling it empty?
> Or even if it doesn't: if what you have is a truly valid DT, then why
> not adapt drivers/of/platform.c to cater for your use-case? Then you
> could take your pick from whatever works better for you out of
> of_platform_populate(), 'simple-bus' or even 'simple-mfd'.
I asked 3 years ago whether there's any interest in expanding
of_platform_populate() for IORESOURCE_REG and there wasn't any response.
It's a big task with overreaching side effects and you don't just pick
up on this on a Friday afternoon.
> > > given the points you've put forward, I would be content for you to
> > > house the child device registration (via mfd_add_devices) in
> > > drivers/mfd if you so wish.
> >
> > Thanks! But I don't know how this helps me :)
> >
> > Since your offer involves changing dt-bindings in order to separate the
> > MFD parent from the DSA switch (currently the DSA driver probes on the
> > spi_device, clashing with the MFD parent which wants the same thing), I
> > will have to pass.
>
> I haven't taken a look at the DT bindings in close enough detail to
> provide a specific solution, but _perhaps_ it would be possible to match
> the MFD driver to the existing compatible, then use the MFD driver to
> register the current DSA driver.
The MFD driver and the DSA driver would compete for the same OF node.
And again, you'd still return to the problem of where to attach the DSA
switch's sub-devices in the device tree (currently to the "mdios" and
"regs" child nodes, which MFD doesn't support probing on, unless we
apply the mfd_cell.parent_of_node patch).
> However, after this most recent exchange, I am even less confident that
> using the MFD API to register only 2 MDIO controllers is the right thing
> to do.
>
> > Not because I insist on being difficult, but because I know that when I
> > change dt-bindings, the old ones don't just disappear and will continue
> > to have to be supported, likely through a separate code path that would
> > also increase code complexity.
>
> Right, they have to be backwardly compatible, I get that.
>
> > > Although I still don't think modifying the core to ignore bespoke empty
> > > "container" nodes is acceptable. It looks like this was merged without
> > > a proper DT review. I'm surprised that this was accepted.
> >
> > There was a debate when this was accepted, but we didn't come up with
> > anything better to fulfill the following constraints:
> > - As per mdio.yaml, the $nodename has to follow the pattern:
> > '^mdio(-(bus|external))?(@.+|-([0-9]+))?$'
> > - There are two MDIO buses. So we have to choose the variant with a
> > unit-address (both MDIO buses are for internal PHYs, so we can't call
> > one "mdio" and the other "mdio-external").
> > - Nodes with a unit address can't be hierarchical neighbours with nodes
> > with no unit address (concretely: "ethernet-ports" from
> > Documentation/devicetree/bindings/net/ethernet-switch.yaml, the main
> > schema that the DSA switch conforms to). This is because their parent
> > either has #address-cells = <0>, or #address-cells = <1>. It can't
> > simultaneously have two values.
> >
> > Simply put, there is no good place to attach child nodes with unit
> > addresses to a DT node following the DSA (or the more general
> > ethernet-switch) schema. The "mdios" container node serves exactly that
> > adaptation purpose.
> >
> > I am genuinely curious how you would have handled this better, so that I
> > also know better next time when I'm in a similar situation.
> >
> > Especially since "mdios" is not the only container node with this issue.
> > The "regs" node proposed in patch 14 serves exactly the same purpose
> > (#address-cells adaptation), and needs the exact same ".parent_of_node = regs_node"
> > workaround in the mfd_cell.
>
> Please correct me if I'm wrong, but from what I have gathered, all
> you're trying to do here is probe a couple of child devices
> (controllers, whatever) and you've chosen to use MFD for this purpose
> because the other, more generic machinery that would normally _just
> work_ for simple scenarios like this, do not because you are attempting
> to support a non-standard DT. Or at least one that isn't supported.
Sorry, what makes the DT non-standard?
> With that in mind, some suggestions going forward in order of preference:
>
> - Adapt the current auto-registering infrastructure to support your DT layout
> - of_platform_populate(), simple-bus, simple-mfd, etc
> - Use fundamental / generic / flexible APIs that do not have specific rules
> - platform_*()
> - Move the mfd_device_add() usage into drivers/mfd
> - Although after this exchange, this is now my least preferred option
I could explore other options, but I want to be prepared to answer other
maintainers' question "why didn't you use MFD?". There is no clear
answer to that, you are not providing answers that have taken all
evidence into account, so that is why I'm being extremely pushy, sorry.
> Hope that helps. Good luck with however you decide to proceed.
>
> --
> Lee Jones [李琼斯]
On Fri, 16 Jan 2026, Vladimir Oltean wrote:
> On Fri, Jan 16, 2026 at 08:40:21AM +0000, Lee Jones wrote:
> > On Thu, 15 Jan 2026, Vladimir Oltean wrote:
> >
> > > On Thu, Jan 15, 2026 at 04:14:07PM +0000, Lee Jones wrote:
> > > > > > My plan, when and if I manage to find a few spare cycles, is to remove
> > > > > > MFD use from outside drivers/mfd. That's been my rule since forever.
> > > > > > Having this in place ensures that the other rules are kept and (mild)
> > > > > > chaos doesn't ensue. The MFD API is trivial to abuse. You wouldn't
> > > > > > believe some of things I've seen over the years. Each value I have is
> > > > > > there for a historical reason.
> > > > >
> > > > > If you're also of the opinion that MFD is a Linux-specific
> > > > > implementation detail and a figment of our imagination as developers,
> > > > > then I certainly don't understand why Documentation/devicetree/bindings/mfd/
> > > > > exists for this separate device class that is MFD, and why you don't
> > > > > liberalize access to mfd_add_devices() instead.
> > > >
> > > > The first point is a good one. It mostly exists for historical
> > > > reasons and for want of a better place to locate the documentation.
> > > >
> > > > I've explained why liberalising the mfd_*() API is a bad idea. "Clever"
> > > > developers like to do some pretty crazy stuff involving the use of
> > > > multiple device registration APIs simultaneously. I've also seen some
> > > > bonkers methods of dynamically populating MFD cells [*ahem* Patch 8
> > > > =;-)] and various other things. Keeping the API in-house allows me to
> > > > keep things simple, easily readable and maintainable.
> > >
> > > The only thing that's crazy to me is how the MFD documentation (+ my
> > > intuition as engineer to fill in the gaps where the documentation was
> > > lacking, aka in a lot of places) could be so far off from what you lay
> > > out as your maintainer expectations here.
> >
> > MFD has documentation? =;-)
> >
> > /me `find . | grep -i mfd`s
> >
> > Okay, the only "MFD documentation" I can find is:
> >
> > Documentation/devicetree/bindings/mfd/mfd.txt
>
> Exactly my point!
>
> > The first paragraph reflects the point I've been trying to make:
> >
> > "These devices comprise a nexus for HETEROGENEOUS hardware blocks
> > containing more than one non-unique yet VARYING HARDWARE FUNCTIONALITY.
> >
> > 2 MDIO controllers are homogeneous to each other and are not varying.
>
> I get the impression you didn't look at patch 14, where I also added the
> ethernet-pcs blocks to MFD children.
That could well be one of the issues.
Please send me the full and finalised DTS hunk.
> > How is the documentation and what I say "so far off"?
>
> Well, it's far off because I got the genuine impression that I'm making
> legitimate use of the MFD API.
That doesn't sound like a lack of parity between the docs and my views,
as previously suggested. The cited doc appears to be in precise
alignment with respect to the points I've been trying to communicate
with you.
> > Okay, so these are the MDIO bus controllers - that's clear now, thank you.
> >
> > I was confused by the t1 and tx parts. Are these different types of
> > MDIO controllers or are they the same, but vary only in support / role?
> >
> > But again, if these are "both MDIO controllers", then they are _same_.
>
> Their register map (i.e. way of accessing the underlying MDIO devices,
> aka internal PHYs) is different. They have different drivers, one is
> added by patch 3 and the other by patch 4.
> Here is the link to the entire set:
> https://lore.kernel.org/netdev/20251118190530.580267-1-vladimir.oltean@nxp.com/
Okay, so if we can say that the MDIO devices are different enough,
despite the nomenclature and that there are additional devices
(Ethernet), then one of the contentious issues can be put to one side.
> > > > > Let me reframe what I think you are saying.
> > > > >
> > > > > If the aesthetics of the dt-bindings of my SPI device were like this (1):
> > > > >
> > > > > (...)
> > > > >
> > > > > then you wouldn't have had any issue about this not being MFD, correct?
> > > >
> > > > Right. This is more in-line with what I would expect to see.
> > > >
> > > > > I think this is an important base fact to establish.
> > > > > It looks fairly similar to Colin Foster's bindings for VSC7512, save for
> > > > > the fact that the sub-devices are slightly more varied (which is inconsequential,
> > > > > as Andrew seems to agree).
> > > > >
> > > > > However, the same physical reality is being described in these _actual_
> > > > > dt-bindings (2):
> > > > >
> > > > > (...)
> > > > >
> > > > > Your issue is that, when looking at these real dt-bindings,
jj> > > > > superficially the MDIO buses don't "look" like MFD.
> > > > >
> > > > > To which, yes, I have no objection, they don't look like MFD because
> > > > > they were written as additions on top of the DSA schema structure, not
> > > > > according to the MFD schema.
> > > > >
> > > > > In reality it doesn't matter much where the MDIO bus nodes are (they
> > > > > could have been under "regs" as well, or under "mfd@0"), because DSA
> > > > > ports get references to their children using phandles. It's just that
> > > > > they are _already_ where they are, and moving them would be an avoidable
> > > > > breaking change.
> > > >
> > > > Right. I think this is highly related to one of my previous comments.
> > > >
> > > > I can't find it right now, but it was to the tune of; if a single driver
> > > > provides lots of functionality that _could_ be split-up, spread across
> > > > multiple different subsystems which all enumerate as completely
> > > > separate device-drivers, but isn't, then it still shouldn't meet the
> > > > criteria.
> > >
> > > Any arbitrary set of distinct functions can be grouped into a new
> > > monolithic driver. Are you saying that grouping them together is fine,
> > > but never split them back up, at least not using MFD? What's the logic?
> >
> > No, the opposite I think?
> >
> > I'm saying that when they are grouped into a monolithic driver, they do
> > not match the criteria of an MFD, but if the _varying_ functionality was
> > split-up and probed individually, they would. Take this example:
> >
> > # Bad
> > static struct mfd_cell cells[] = {
> > MFD_CELL_NAME("abc-monolithic")
> > };
> >
> > # Bad
> > static struct mfd_cell cells[] = {
> > MFD_CELL_NAME("abc-function-a")
> > MFD_CELL_NAME("abc-function-a")
> > };
> >
> > # Good
> > static struct mfd_cell cells[] = {
> > MFD_CELL_NAME("abc-function-a")
> > MFD_CELL_NAME("abc-function-b")
> > };
> >
> > At the moment, from what I see in front of me, you are the middle one.
>
> I think you are missing patch 14.
Right, I hadn't seen that.
Would I be correct in saying that you're pulling out information from
DT, then populating MFD cells with it? If so, that is one of the
reasons I like to be able to keep an eye on how the MFD API is being
used. Populating one device registration API from another is also not
allowed and has been the source of some of the most contentious
submissions I've seen.
Looks like I briefly mentioned this before:
"I've explained why liberalising the mfd_*() API is a bad idea. "Clever"
developers like to do some pretty crazy stuff involving the use of
MULTIPLE DEVICE REGISTRATION APIS SIMULTANEOUSLY. I've also seen some <-----------
bonkers methods of DYNAMICALLY POPULATING MFD CELLS [*ahem* Patch 8 <-----------
=;-)] and various other things. Keeping the API in-house allows me to
keep things simple, easily readable and maintainable."
Add in a few function pointers to be used as un-debugable call-backs and
you're well on the way getting a perfect score for breaking all of the
guidelines that I use to keep code "simple, easily readable and
maintainable"! ;)
> Although for SJA1105R/S, I am indeed in the middle position (it has to
> do with the multi-generational aspect I was telling you about).
>
> > > > > Exactly. DSA drivers get more developed with new each new hardware
> > > > > generation, and you wouldn't want to see an MFD driver + its bindings
> > > > > "just in case" new sub-devices will appear, when currently the DSA
> > > > > switch is the only component supported by Linux (and maybe its internal
> > > > > MDIO bus).
> > > >
> > > > If only one device is currently supported, then again, it doesn't meet
> > > > the criteria. I've had a bunch of developers attempt to upstream
> > > > support for a single device and insist that more sub-devices are coming
> > > > which would make it an MFD, but that's not how it works. Devices must
> > > > meet the criteria _now_. So I usually ask them go take the time to get
> > > > at least one more device ready before attempting to upstream.
> > >
> > > sja1105 is a multi-generational DSA driver. Gen 1 SJA1105E/T has 0
> > > sub-devices, Gen 2 SJA1105R/S have 1 sub-device (XPCS) and Gen3 SJA1110
> > > have 5+ sub-devices.
> > >
> > > The driver was written for Gen 1, then was expanded for the later
> > > generations as the silicon was released (multiple years in between these
> > > events).
> > >
> > > You are effectively saying:
> > > - MAX77540 wouldn't have been accepted as MFD on its own, it was
> > > effectively carried in by MAX77541 support.
> > > - A driver that doesn't have sufficiently varied subfunctions doesn't
> > > qualify as MFD.
> > > - A monolithic driver whose subfunctions can be split up doesn't meet
> > > the MFD criteria.
> >
> > If it "can", but isn't, then it doesn't, that's correct.
> >
> > But if it _is_ split-up then it does.
> >
> > > So in your rule system, a multi-generational driver which evolves into
> > > having multiple sub-devices has no chance of ever using MFD, unless it
> > > is written after the evolution has stopped, and the old generations
> > > become obsolete.
> >
> > I'm really not. I'm saying that if the driver were to be spit-up, then
> > it _would_ match the criteria and it would be free to use MFD to
> > register those split-up sub-devices.
>
> I don't know what you meant to say, but I quote what you actually said,
> and how I interpreted it:
>
> "if a single driver provides lots of functionality that _could_ be
> split-up, (...), but isn't [ split up ], then it still shouldn't meet
> the criteria [ for using the MFD API ]."
That's correct. I stand by that.
... but if it is split-up into heterogeneous parts which get registered
separately then it should meet the criteria.
You're hearing "once driver has been merged, it cannot be split-up in
such as way that the MFD API cannot be used" and I'm saying the exact
opposite of that. It absolutely can be used if the new layout meets the
criteria.
I'm not sure how much more I can make it.
> > > Unless you're of the opinion that it's my fault for not predicting
> > > the future and waiting until the SJA1110 came out in order to
> > > write an MFD driver, I suggest you could reconsider your rules so
> > > that they're less focused on your comfort as maintainer, at the
> > > expense of fairness and coherency for other developers.
> >
> > This isn't what I've said at all.
> >
> > What I have said is that even though you've split this up, you have
> > only split it up into 2 homogeneous devices / controllers, which
> > still does not qualify.
> >
> > If you have plans to split out another varying function, other than
> > an MDIO controller, then do so and you can then easily qualify.
>
> Ok, so we're getting close, you just need to take a look at patch 14.
I have looked at that now. And yes, it solves this problem.
However, as I've explained above, it creates another.
> > > > Is there any reason not to put mdio_cbt and mdio_cbt1 resources
> > > > into the device tree
> > >
> > > That ship has sailed and there are device trees in circulation
> > > with existing mdio_cbtx/mdio_cbt1 bindings.
> > >
> > > > or make them available somewhere else (e.g.
> > > > driver.of_match_table.data) and use of_platform_populate()
> > > > instead of mfd_add_devices() (I can't remember if we've
> > > > suggested that before or not).
> > >
> > > I never got of_platform_populate() to work for a pretty
> > > fundamental reason, so I don't have enough information to know
> > > what you're on about with making the mdio_cbtx/mdio_cbt1 resources
> > > available to it.
> > >
> > > > Right, I think we've discussed this enough. I've made a
> > > > decision.
> > > >
> > > > If the of_platform_populate() solution doesn't work for you for
> > > > some reason (although I think it should),
> > >
> > > Quote from the discussion on patch 8:
> > >
> > > I did already explore of_platform_populate() on this thread which
> > > asked for advice (to which you were also copied):
> > > https://lore.kernel.org/lkml/20221222134844.lbzyx5hz7z5n763n@skbuf/
> > >
> > > It looks like of_platform_populate() would be an alternative
> > > option for this task, but that doesn't live up to the task
> > > either. It will assume that the addresses of the SoC children
> > > are in the CPU's address space (IORESOURCE_MEM), and attempt
> > > to translate them. It simply doesn't have the concept of
> > > IORESOURCE_REG. The MFD drivers which call
> > > of_platform_populate() (simple-mfd-i2c.c) simply don't have
> > > unit addresses for their children, and this is why address
> > > translation isn't a problem for them.
> > >
> > > In fact, this seems to be a rather large limitation of
> > > include/linux/of_address.h. Even something as simple as
> > > of_address_count() will end up trying to translate the address
> > > into the CPU memory space, so not even open-coding the
> > > resource creation in the SoC driver is as simple as it
> > > appears.
> > >
> > > Is there a better way than completely open-coding the parsing
> > > of the OF addresses when turning them into IORESOURCE_REG
> > > resources (or open-coding mfd_cells for each child)? Would
> > > there be a desire in creating a generic set of helpers which
> > > create platform devices with IORESOURCE_REG resources, based
> > > solely on OF addresses of children? What would be the correct
> > > scope for these helpers?
> >
> > Does this all boil down that pesky empty 'mdio' "container"?
>
> Why do you keep calling it empty?
Because it has no compatible, unit address or any of its own values,
which appears to make it untraversable using the present machinery.
> > Or even if it doesn't: if what you have is a truly valid DT, then
> > why not adapt drivers/of/platform.c to cater for your use-case?
> > Then you could take your pick from whatever works better for you out
> > of of_platform_populate(), 'simple-bus' or even 'simple-mfd'.
>
> I asked 3 years ago whether there's any interest in expanding
> of_platform_populate() for IORESOURCE_REG and there wasn't any
> response. It's a big task with overreaching side effects and you don't
> just pick up on this on a Friday afternoon.
Enjoy your weekend - we can wait until Monday! ;)
There clearly wasn't any other users. Or at least people that haven't
found other ways around the issue. But if you need it, and you can
justify the work with a clear use-case, write support for it.
> > > > given the points you've put forward, I would be content for you
> > > > to house the child device registration (via mfd_add_devices) in
> > > > drivers/mfd if you so wish.
> > >
> > > Thanks! But I don't know how this helps me :)
> > >
> > > Since your offer involves changing dt-bindings in order to
> > > separate the MFD parent from the DSA switch (currently the DSA
> > > driver probes on the spi_device, clashing with the MFD parent
> > > which wants the same thing), I will have to pass.
> >
> > I haven't taken a look at the DT bindings in close enough detail to
> > provide a specific solution, but _perhaps_ it would be possible to
> > match the MFD driver to the existing compatible, then use the MFD
> > driver to register the current DSA driver.
>
> The MFD driver and the DSA driver would compete for the same OF node.
> And again, you'd still return to the problem of where to attach the
> DSA switch's sub-devices in the device tree (currently to the "mdios"
> and "regs" child nodes, which MFD doesn't support probing on, unless
> we apply the mfd_cell.parent_of_node patch).
No, the MFD driver would adopt the compatible and register the DSA
driver for device-driver matching. You could then obtain the node for
parsing the DSA using node->parent.
I suspect you'd be better off manually crawling through the 'mdio' cell
in the child drivers using node->parent.
> > However, after this most recent exchange, I am even less confident
> > that using the MFD API to register only 2 MDIO controllers is the
> > right thing to do.
> >
> > > Not because I insist on being difficult, but because I know that
> > > when I change dt-bindings, the old ones don't just disappear and
> > > will continue to have to be supported, likely through a separate
> > > code path that would also increase code complexity.
> >
> > Right, they have to be backwardly compatible, I get that.
> >
> > > > Although I still don't think modifying the core to ignore
> > > > bespoke empty "container" nodes is acceptable. It looks like
> > > > this was merged without a proper DT review. I'm surprised that
> > > > this was accepted.
> > >
> > > There was a debate when this was accepted, but we didn't come up
> > > with anything better to fulfill the following constraints: - As
> > > per mdio.yaml, the $nodename has to follow the pattern:
> > > '^mdio(-(bus|external))?(@.+|-([0-9]+))?$' - There are two MDIO
> > > buses. So we have to choose the variant with a unit-address (both
> > > MDIO buses are for internal PHYs, so we can't call one "mdio" and
> > > the other "mdio-external"). - Nodes with a unit address can't be
> > > hierarchical neighbours with nodes with no unit address
> > > (concretely: "ethernet-ports" from
> > > Documentation/devicetree/bindings/net/ethernet-switch.yaml, the
> > > main schema that the DSA switch conforms to). This is because
> > > their parent either has #address-cells = <0>, or #address-cells =
> > > <1>. It can't simultaneously have two values.
> > >
> > > Simply put, there is no good place to attach child nodes with unit
> > > addresses to a DT node following the DSA (or the more general
> > > ethernet-switch) schema. The "mdios" container node serves exactly
> > > that adaptation purpose.
> > >
> > > I am genuinely curious how you would have handled this better, so
> > > that I also know better next time when I'm in a similar situation.
> > >
> > > Especially since "mdios" is not the only container node with this
> > > issue. The "regs" node proposed in patch 14 serves exactly the
> > > same purpose (#address-cells adaptation), and needs the exact same
> > > ".parent_of_node = regs_node" workaround in the mfd_cell.
> >
> > Please correct me if I'm wrong, but from what I have gathered, all
> > you're trying to do here is probe a couple of child devices
> > (controllers, whatever) and you've chosen to use MFD for this
> > purpose because the other, more generic machinery that would
> > normally _just work_ for simple scenarios like this, do not because
> > you are attempting to support a non-standard DT. Or at least one
> > that isn't supported.
>
> Sorry, what makes the DT non-standard?
The fact that the current OF APIs can't parse / traverse it.
> > With that in mind, some suggestions going forward in order of
> > preference:
> >
> > - Adapt the current auto-registering infrastructure to support your
> > DT layout - of_platform_populate(), simple-bus, simple-mfd, etc -
> > Use fundamental / generic / flexible APIs that do not have specific
> > rules - platform_*() - Move the mfd_device_add() usage into
> > drivers/mfd - Although after this exchange, this is now my least
> > preferred option
>
> I could explore other options, but I want to be prepared to answer
> other maintainers' question "why didn't you use MFD?". There is no
> clear answer to that, you are not providing answers that have taken
> all evidence into account, so that is why I'm being extremely pushy,
> sorry.
That's fine. If questioned, point them to this summary:
What you're doing here; attempting to reverse engineer old DTBs by
extracting information from them to populate a different device
registration API (DT, MFD, Plat, ACPI, etc) is not suitable for MFD due
to reasons pertaining to; keeping things simple, easily readable and
maintainable (see Patch 14 for an example of this).
- MFDs should contain multiple, varying, heterogeneous devices
- MFD parents should only use one registration API at a time
- The MFD API should not be used outside of drivers/mfd
- Dynamically allocating mfd_cells is STRONGLY discouraged
If you think that you can match all of the above criteria, then you may
use the MFD API. If not, then it is not suitable for your use-case and
you should seek other means of device registration. I suggest;
of_platform_populate(), platform_add_devices() [and friends],
'simple-bus' and 'simple-mfd', although I'm sure there are others.
--
Lee Jones [李琼斯]
On Fri, Jan 16, 2026 at 01:23:45PM +0000, Lee Jones wrote:
> Please send me the full and finalised DTS hunk.
I gave it to you earlier in this thread, it is (2) from:
https://lore.kernel.org/netdev/20260109121432.lu2o22iijd4i57qq@skbuf/
(the actual device tree has more irrelevant properties, the above is
just the relevant skeleton)
With the mention that in current device trees, the "regs" node and its
underlying hierachy is missing, and patch 14 from this patch set uses
the of_changeset API to dynamically fill it in before calling
mfd_add_devices().
> > I think you are missing patch 14.
>
> Right, I hadn't seen that.
>
> Would I be correct in saying that you're pulling out information from
> DT, then populating MFD cells with it?
No.
I am _creating_ information in DT based on hardcoded resources in the
driver, in order to probe MFD children on them.
The reason is because I didn't need to describe those children in DT
thus far, and still don't, except for the situation where they need to
operate in a non-default configuration, which is board-specific.
More concretely, I need board DTS writers to be able to add the
"rx-polarity" and "tx-polarity" properties to the ethernet-pcs children.
These properties are handled by a different driver. The DSA driver
stands in their way, so this patch set gives an OF node to the
ethernet-pcs driver to customize whatever it needs.
If no custom DT property needs to be specified by the board, it can just
as well omit specifying the "regs" node and its children, and the driver
will fill it in all the same.
> If so, that is one of the
> reasons I like to be able to keep an eye on how the MFD API is being
> used. Populating one device registration API from another is also not
> allowed and has been the source of some of the most contentious
> submissions I've seen.
>
> Looks like I briefly mentioned this before:
>
> "I've explained why liberalising the mfd_*() API is a bad idea. "Clever"
> developers like to do some pretty crazy stuff involving the use of
> MULTIPLE DEVICE REGISTRATION APIS SIMULTANEOUSLY. I've also seen some <-----------
> bonkers methods of DYNAMICALLY POPULATING MFD CELLS [*ahem* Patch 8 <-----------
> =;-)] and various other things. Keeping the API in-house allows me to
> keep things simple, easily readable and maintainable."
>
> Add in a few function pointers to be used as un-debugable call-backs and
> you're well on the way getting a perfect score for breaking all of the
> guidelines that I use to keep code "simple, easily readable and
> maintainable"! ;)
Ok, but this is highly subjective to you. What you call "simple, easily
readable and maintainable" I can just as well call "does not scale
beyond sticks and stones".
> ... but if it is split-up into heterogeneous parts which get registered
> separately then it should meet the criteria.
>
> You're hearing "once driver has been merged, it cannot be split-up in
> such as way that the MFD API cannot be used" and I'm saying the exact
> opposite of that. It absolutely can be used if the new layout meets the
> criteria.
>
> I'm not sure how much more I can make it.
The (DT) layout is given by the driver's history as non-MFD.
> > > Does this all boil down that pesky empty 'mdio' "container"?
> >
> > Why do you keep calling it empty?
>
> Because it has no compatible, unit address or any of its own values,
> which appears to make it untraversable using the present machinery.
The fact that the unit addresses are untraversable by the OF address API
is exactly the issue. They are addresses in the address space of the
Ethernet switch chip, you can't memory-map them into Linux, you have to
go through switch-specific SPI reads and writes to access them. Then you
wrap those SPI reads and writes into regmap, and you can present them to
platform device drivers and they (almost) wouldn't know any better.
> > > Or even if it doesn't: if what you have is a truly valid DT, then
> > > why not adapt drivers/of/platform.c to cater for your use-case?
> > > Then you could take your pick from whatever works better for you out
> > > of of_platform_populate(), 'simple-bus' or even 'simple-mfd'.
> >
> > I asked 3 years ago whether there's any interest in expanding
> > of_platform_populate() for IORESOURCE_REG and there wasn't any
> > response. It's a big task with overreaching side effects and you don't
> > just pick up on this on a Friday afternoon.
>
> Enjoy your weekend - we can wait until Monday! ;)
>
> There clearly wasn't any other users. Or at least people that haven't
> found other ways around the issue. But if you need it, and you can
> justify the work with a clear use-case, write support for it.
I'm not convinced that I won't be wasting my time.
I already know that this will be the case for the MDIO buses, because I
didn't have the inspiration at the time to create a "regs" node and to
describe their resource there. So their unit address is a random
"mdio@0" and "mdio@1", and obviously of_platform_populate() ->
of_address_to_resource() can't work with that.
For the children of the "regs" node, maybe this could help, but then I'd
run into the "multiple registration APIs being used" thing that you also
dislike (and which is currently _not_ the case).
So I pretty much know that of_platform_populate() won't help with my
currently established dt-bindings. Changing them is highly unattractive.
> > > > > given the points you've put forward, I would be content for you
> > > > > to house the child device registration (via mfd_add_devices) in
> > > > > drivers/mfd if you so wish.
> > > >
> > > > Thanks! But I don't know how this helps me :)
> > > >
> > > > Since your offer involves changing dt-bindings in order to
> > > > separate the MFD parent from the DSA switch (currently the DSA
> > > > driver probes on the spi_device, clashing with the MFD parent
> > > > which wants the same thing), I will have to pass.
> > >
> > > I haven't taken a look at the DT bindings in close enough detail to
> > > provide a specific solution, but _perhaps_ it would be possible to
> > > match the MFD driver to the existing compatible, then use the MFD
> > > driver to register the current DSA driver.
> >
> > The MFD driver and the DSA driver would compete for the same OF node.
> > And again, you'd still return to the problem of where to attach the
> > DSA switch's sub-devices in the device tree (currently to the "mdios"
> > and "regs" child nodes, which MFD doesn't support probing on, unless
> > we apply the mfd_cell.parent_of_node patch).
>
> No, the MFD driver would adopt the compatible and register the DSA
> driver for device-driver matching. You could then obtain the node for
> parsing the DSA using node->parent.
By node->parent do you actually mean device_set_node(dsa_dev, mfd_dev->fwnode)?
We're not addressing the central problem that the spi_device doesn't
have DT bindings that conform to both the DSA expectations and to the
MFD expectations. That's where my "regs" node comes in, but you don't
like it because it involves the parent_of_node patch.
> I suspect you'd be better off manually crawling through the 'mdio' cell
> in the child drivers using node->parent.
>
> > > However, after this most recent exchange, I am even less confident
> > > that using the MFD API to register only 2 MDIO controllers is the
> > > right thing to do.
> > >
> > > > Not because I insist on being difficult, but because I know that
> > > > when I change dt-bindings, the old ones don't just disappear and
> > > > will continue to have to be supported, likely through a separate
> > > > code path that would also increase code complexity.
> > >
> > > Right, they have to be backwardly compatible, I get that.
> > >
> > > > > Although I still don't think modifying the core to ignore
> > > > > bespoke empty "container" nodes is acceptable. It looks like
> > > > > this was merged without a proper DT review. I'm surprised that
> > > > > this was accepted.
> > > >
> > > > There was a debate when this was accepted, but we didn't come up
> > > > with anything better to fulfill the following constraints: - As
> > > > per mdio.yaml, the $nodename has to follow the pattern:
> > > > '^mdio(-(bus|external))?(@.+|-([0-9]+))?$' - There are two MDIO
> > > > buses. So we have to choose the variant with a unit-address (both
> > > > MDIO buses are for internal PHYs, so we can't call one "mdio" and
> > > > the other "mdio-external"). - Nodes with a unit address can't be
> > > > hierarchical neighbours with nodes with no unit address
> > > > (concretely: "ethernet-ports" from
> > > > Documentation/devicetree/bindings/net/ethernet-switch.yaml, the
> > > > main schema that the DSA switch conforms to). This is because
> > > > their parent either has #address-cells = <0>, or #address-cells =
> > > > <1>. It can't simultaneously have two values.
> > > >
> > > > Simply put, there is no good place to attach child nodes with unit
> > > > addresses to a DT node following the DSA (or the more general
> > > > ethernet-switch) schema. The "mdios" container node serves exactly
> > > > that adaptation purpose.
> > > >
> > > > I am genuinely curious how you would have handled this better, so
> > > > that I also know better next time when I'm in a similar situation.
> > > >
> > > > Especially since "mdios" is not the only container node with this
> > > > issue. The "regs" node proposed in patch 14 serves exactly the
> > > > same purpose (#address-cells adaptation), and needs the exact same
> > > > ".parent_of_node = regs_node" workaround in the mfd_cell.
> > >
> > > Please correct me if I'm wrong, but from what I have gathered, all
> > > you're trying to do here is probe a couple of child devices
> > > (controllers, whatever) and you've chosen to use MFD for this
> > > purpose because the other, more generic machinery that would
> > > normally _just work_ for simple scenarios like this, do not because
> > > you are attempting to support a non-standard DT. Or at least one
> > > that isn't supported.
> >
> > Sorry, what makes the DT non-standard?
>
> The fact that the current OF APIs can't parse / traverse it.
Are there any standards in this area that I can refer to?
>
> > > With that in mind, some suggestions going forward in order of
> > > preference:
> > >
> > > - Adapt the current auto-registering infrastructure to support your
> > > DT layout - of_platform_populate(), simple-bus, simple-mfd, etc -
> > > Use fundamental / generic / flexible APIs that do not have specific
> > > rules - platform_*() - Move the mfd_device_add() usage into
> > > drivers/mfd - Although after this exchange, this is now my least
> > > preferred option
> >
> > I could explore other options, but I want to be prepared to answer
> > other maintainers' question "why didn't you use MFD?". There is no
> > clear answer to that, you are not providing answers that have taken
> > all evidence into account, so that is why I'm being extremely pushy,
> > sorry.
>
> That's fine. If questioned, point them to this summary:
>
> What you're doing here; attempting to reverse engineer old DTBs by
> extracting information from them to populate a different device
> registration API (DT, MFD, Plat, ACPI, etc) is not suitable for MFD due
> to reasons pertaining to; keeping things simple, easily readable and
> maintainable (see Patch 14 for an example of this).
>
> - MFDs should contain multiple, varying, heterogeneous devices
Check
> - MFD parents should only use one registration API at a time
Check
> - The MFD API should not be used outside of drivers/mfd
Not fulfilled, although I'm sorry to say, but if it comes only to this,
and the alternatives are of much higher complexity, then I'm not sure
that it really makes sense to NACK based on this.
> - Dynamically allocating mfd_cells is STRONGLY discouraged
This comes from the multi-generational issue I am talking about (not all
generations have the same children), and dynamically generating the
cells was the most elegant way to avoid these warnings in mfd_add_device():
match:
if (!pdev->dev.of_node)
pr_warn("%s: Failed to locate of_node [id: %d]\n",
cell->name, platform_id);
aka never provide a cell for a child you know you don't have.
>
> If you think that you can match all of the above criteria, then you may
> use the MFD API. If not, then it is not suitable for your use-case and
> you should seek other means of device registration. I suggest;
> of_platform_populate(), platform_add_devices() [and friends],
> 'simple-bus' and 'simple-mfd', although I'm sure there are others.
>
> --
> Lee Jones [李琼斯]
On Fri, Jan 16, 2026 at 04:02:37PM +0200, Vladimir Oltean wrote:
> On Fri, Jan 16, 2026 at 01:23:45PM +0000, Lee Jones wrote:
> > Please send me the full and finalised DTS hunk.
>
> I gave it to you earlier in this thread, it is (2) from:
> https://lore.kernel.org/netdev/20260109121432.lu2o22iijd4i57qq@skbuf/
> (the actual device tree has more irrelevant properties, the above is
> just the relevant skeleton)
>
> With the mention that in current device trees, the "regs" node and its
> underlying hierachy is missing, and patch 14 from this patch set uses
> the of_changeset API to dynamically fill it in before calling
> mfd_add_devices().
I am a bit torn between not wanting to confuse you by providing
irrelevant information, and not giving the impression that those
properties are all that there is.
The ethernet-switch root node also has all DSA properties that can be
seen in the Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml
example. The above properties are all overlaid on top.
Merged together, they would look like this:
spi {
#address-cells = <1>;
#size-cells = <0>;
sw1: ethernet-switch@0 {
compatible = "nxp,sja1110a";
reg = <0>; // means "SPI chip select"
ethernet-ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
};
port@1 {
reg = <1>;
pcs-handle = <&sgmii1_pcs>;
};
port@2 {
reg = <2>;
pcs-handle = <&sgmii2_pcs>;
fixed-link {
speed = <1000>;
full-duplex;
};
};
port@3 {
reg = <3>;
pcs-handle = <&sgmii3_pcs>;
};
sw1p4: port@4 {
reg = <4>;
pcs-handle = <&sgmii4_pcs>;
};
port@5 {
reg = <5>;
phy-handle = <&sw1_port5_base_t1_phy>;
};
port@6 {
reg = <6>;
phy-handle = <&sw1_port6_base_t1_phy>;
};
port@7 {
reg = <7>;
phy-handle = <&sw1_port7_base_t1_phy>;
};
port@8 {
reg = <8>;
phy-handle = <&sw1_port8_base_t1_phy>;
};
port@9 {
reg = <9>;
phy-handle = <&sw1_port9_base_t1_phy>;
};
port@a {
reg = <10>;
phy-handle = <&sw1_port10_base_t1_phy>;
};
};
mdios {
#address-cells = <1>;
#size-cells = <0>;
mdio@0 {
compatible = "nxp,sja1110-base-t1-mdio";
#address-cells = <1>;
#size-cells = <0>;
reg = <0>; // 0 has no physical meaning other than "first bus"
sw1_port5_base_t1_phy: ethernet-phy@1 {
compatible = "ethernet-phy-ieee802.3-c45";
reg = <0x1>;
};
sw1_port6_base_t1_phy: ethernet-phy@2 {
compatible = "ethernet-phy-ieee802.3-c45";
reg = <0x2>;
};
sw1_port7_base_t1_phy: ethernet-phy@3 {
compatible = "ethernet-phy-ieee802.3-c45";
reg = <0x3>;
};
sw1_port8_base_t1_phy: ethernet-phy@4 {
compatible = "ethernet-phy-ieee802.3-c45";
reg = <0x4>;
};
sw1_port9_base_t1_phy: ethernet-phy@5 {
compatible = "ethernet-phy-ieee802.3-c45";
reg = <0x5>;
};
sw1_port10_base_t1_phy: ethernet-phy@6 {
compatible = "ethernet-phy-ieee802.3-c45";
reg = <0x6>;
};
};
mdio@1 {
compatible = "nxp,sja1110-base-tx-mdio";
#address-cells = <1>;
#size-cells = <0>;
reg = <1>; // no physical meaning other than "second bus"
ethernet-phy@0 {
reg = <0x0>;
};
};
};
/* The portion above is established binding. The portion below isn't */
regs {
#address-cells = <1>;
#size-cells = <1>;
/* The bindings of these PCS devices all come
* from Documentation/devicetree/bindings/net/pcs/snps,dw-xpcs.yaml,
* they are not defined by me.
*/
sgmii1_pcs: ethernet-pcs@705000 { // Physical meaning: untranslatable switch address space
compatible = "nxp,sja1110-pcs";
reg = <0x705000 0x1000>;
reg-names = "indirect";
};
sgmii2_pcs: ethernet-pcs@706000 {
compatible = "nxp,sja1110-pcs";
reg = <0x706000 0x1000>;
reg-names = "indirect";
rx-polarity = <PHY_POL_INVERT>; // THIS LINE is what the entire effort is for.
};
sgmii3_pcs: ethernet-pcs@707000 {
compatible = "nxp,sja1110-pcs";
reg = <0x707000 0x1000>;
reg-names = "indirect";
};
sgmii4_pcs: ethernet-pcs@708000 {
compatible = "nxp,sja1110-pcs";
reg = <0x708000 0x1000>;
reg-names = "indirect";
};
};
};
};
Hi Lee, On Fri, Jan 09, 2026 at 02:14:32PM +0200, Vladimir Oltean wrote: > > When I've thought about replacing the existing occurrences of the MFD > > API being used outside of drivers/mfd, I have often thought of a > > platform_add_device_simple() call which I believe would do what most > > people of these use-cases actually want. > > Would this platform_add_device_simple() share or duplicate code with > mfd_add_devices()? Why not just liberalize mfd_add_devices() (the > simplest solution)? Sorry to nag you, but I would like to have a clear image of which way this patch set needs to be heading for v2. My understanding is that you're pushing for platform_device_add() while not completely rejecting that MFD could be the correct model for this switch's sub-devices.
On Thu, 15 Jan 2026, Vladimir Oltean wrote: > Hi Lee, > > On Fri, Jan 09, 2026 at 02:14:32PM +0200, Vladimir Oltean wrote: > > > When I've thought about replacing the existing occurrences of the MFD > > > API being used outside of drivers/mfd, I have often thought of a > > > platform_add_device_simple() call which I believe would do what most > > > people of these use-cases actually want. > > > > Would this platform_add_device_simple() share or duplicate code with > > mfd_add_devices()? Why not just liberalize mfd_add_devices() (the > > simplest solution)? > > Sorry to nag you, but I would like to have a clear image of which way > this patch set needs to be heading for v2. My understanding is that > you're pushing for platform_device_add() while not completely rejecting > that MFD could be the correct model for this switch's sub-devices. Sorry, lots on. I'll go take a look now. -- Lee Jones [李琼斯]
I acknowledge receipt of your mail, but I need to get my list of reviews down to a sensible number before fully processing it. Please stand-by. / Lee > On Fri, Nov 21, 2025 at 12:06:46PM +0000, Lee Jones wrote: > > MFD is Linuxisum, simply used to split devices up such that each > > component can be located it their own applicable subsystem and be > > reviewed and maintained by the subject matter experts of those domains. > > Perfect, so the SJA1110 fits the MFD bill perfectly. > > I'm getting the impression that the more I write to explain, the fewer > chances I have for you to read. I'll try to keep things as concise as I > can, but please remember that: > - We've had the exact same discussions with Colin Foster's VSC7512 > work, which you ended up accepting > - This email sent to you in 2022 and again in the other reply on patch 8: > https://lore.kernel.org/lkml/20221222134844.lbzyx5hz7z5n763n@skbuf/ > already explains what is the kind of hardware I'm dealing with > > > TL;DR: if your device only deals with Networking, that's where it should > > live. And from there, it should handle its own device registration and > > instantiation without reaching into other, non-related subsystems. > > Ok, you make a vague reference which I think I understand the point of. > > I need to merge the discussion with the one from patch 8: > https://lore.kernel.org/netdev/20251121120037.GA1117685@google.com/ > where you say: > > | Another more recent avenue you may explore is the Auxiliary Bus. > > Excerpt from documentation here: > https://docs.kernel.org/driver-api/auxiliary_bus.html > > When Should the Auxiliary Bus Be Used > > (...) > The emphasis here is on a common generic interface that keeps subsystem > customization out of the bus infrastructure. > (...) > A key requirement for utilizing the auxiliary bus is that there is no > dependency on a physical bus, device, register accesses or regmap > support. These individual devices split from the core cannot live on the > platform bus as they are not physical devices that are controlled by > DT/ACPI. The same argument applies for not using MFD in this scenario as > MFD relies on individual function devices being physical devices. > > The thesis I need to defend is that the SJA1110 usage is 100% fit for > MFD and 0% auxiliary bus. In order to explain it I have to give a bit of > history on DSA. > > DSA is a Linuxism for managing Ethernet switches. Key thing is they are > a hardware IP with registers to configure them. There are many ways > to integrate an Ethernet switch hardware IP in a chip that you sell. > You can (a) sell the IP itself for SoC vendors to put in their address > space and access using MMIO, or you can (b) sell them an entire chip > with the switch IP in it, that they access over a bus like PCIe, SPI, > I2C, MDIO, whatever, and integrate with their existing Linux SoC. > > DSA has started from a place where it didn't really understand that its > core domain of expertise was the Ethernet switching IP itself. The first > devices it supported were all of the (b) kind, discrete chips on buses. > Thus, many drivers were written where DSA takes charge of the struct > spi_device, mdio_device, i2c_client etc. > > These early drivers are simplistic, they configure the switch to pass > traffic, and the PHYs through the internal MDIO bus to establish a link, > and voila! They pass traffic, they're good to go. > > Then you start to want to develop these further. You want to avoid > polling PHYs for link status every second.. well, you find there's an > interrupt controller in that chip too, that you should be using with > irqchip. You want to read the chip's temperature to prevent it from > overheating - you find temperature sensors too, for which you register > with hwmon. You find reset blocks, clock generation blocks, power > management blocks, GPIO controllers, what have you. > > See, the more you look at the datasheet, the more you start to notice > an entire universe of hardware IPs, and then.. you notice a microcontroller! > Those hardware IPs are all also memory-mapped in the address space of > that microcontroller, and when you from Linux are accessing them, you're > just going through a SPI-to-AHB bridge. > > Things become really shitty when the DSA chip that you want to drive > from drivers/net/dsa has a full-blown microprocessor capable of running > Linux instead of that microcontroller! Then you have to support driving > the same switch from the small Linux, using MMIO, or from the big Linux, > over SPI. > > Out of a lack of expressivity that we as engineers have, we call both > the SoC at large "a switch", and the switching IP "a switch". Hell, > we even call the rack-mounted pizza box computer with many ports "a switch", > no wonder nobody understands anything! We just name things after the > most important thing that's in them. > > So unwind 100 steps from the rabbit hole and ask: what does DSA concern > itself with? > > Ideally, the answer is "the Ethernet switch IP". This is always mapped > in somebody's address space from address X to Y. > > Practically, legacy makes it that DSA concerns itself with the entire > address space of SPI devices, MDIO devices, I2C devices etc. If you > imagine a microprocessor in these discrete chips (which is architecturally > almost always possible), the device tree of that would only describe a > single region with the Ethernet switching IP, and Linux would probe a > platform device for that. The rest is.. other stuff (of various degrees > of functional relatedness, but nonetheless, other stuff) with *other* > platform devices. > > So, DSA is in a process of trying to define a conversion model that is > coherent, compatible with the past, minimal in its description, > applicable to other devices, and not a pain in the butt. > > Fact of the matter is, we will always clash with the MFD maintainer in > this process, and it simply doesn't scale for us to keep repeating the > same stuff over and over. It is just too much friction. We went through > this once, with Colin Foster who added the Microchip VSC7512 as MFD > through your tree, and that marked the first time when a DSA driver over > a SPI device concerned itself with just the switching IP, using MFD as > the abstraction layer. > > The NXP SJA1110 is just another step in that journey, but this one is > harder because it has legacy device tree bindings to maintain. However, > if we are to accept that Colin Foster's work was not an architectural > mistake, then the SJA1110 is not the end of the road either, and you > have to be prepared for more devices to come and do the same thing. > > So practically speaking, the fact that DSA has these particular needs > is just a fact. Treat the above description as a "global prompt", if you > will :) > > So why not the auxiliary bus? That creates auxiliary_device structures, > which are fake things that some core device wants to keep out to make > things leaner. But what we want is a platform_device, because that is > the common denominator between what kind of drivers the "small Linux" > and the "big Linux" would use for the same hardware IPs. MFD gives us > exactly that, and regmap provides the abstraction between MMIO and SPI. > > ================================================================ > > The above was the "global prompt" that you need to have in your context, > now let's return to the patch at hand. > > SJA1110 is *not* capable of running Linux inside. This allows us to get > away with partial conversions, where the DSA driver still remains in > charge of the entire SPI device, but delegates the other stuff to MFD. > > The existing bindings cannot be broken. Hindsight is 20/20, but whatever > stupid decisions I made in the past with this "mdios" container node are > there to stay. -- Lee Jones [李琼斯]
© 2016 - 2026 Red Hat, Inc.