[PATCH net-next 08/15] net: dsa: sja1105: transition OF-based MDIO drivers to standalone

Vladimir Oltean posted 15 patches 1 week, 6 days ago
[PATCH net-next 08/15] net: dsa: sja1105: transition OF-based MDIO drivers to standalone
Posted by Vladimir Oltean 1 week, 6 days ago
Delete the duplicated drivers for 100base-T1 and 100base-TX from the DSA
driver, and use devm_mfd_add_devices() to platform devices which probe
on the dedicated drivers from drivers/net/mdio/. This makes the switch
act as a sort of bus driver for devices in the "mdios" subnode.

We can use mfd because the switch driver interacts with the PHYs from
these MDIO buses exclusively using phylink, which follows "phy-handle"
fwnode references to them.

Cc: Lee Jones <lee@kernel.org>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
 drivers/net/dsa/sja1105/Kconfig        |   1 +
 drivers/net/dsa/sja1105/Makefile       |   1 +
 drivers/net/dsa/sja1105/sja1105.h      |   4 -
 drivers/net/dsa/sja1105/sja1105_main.c |  13 ++
 drivers/net/dsa/sja1105/sja1105_mdio.c | 270 +------------------------
 drivers/net/dsa/sja1105/sja1105_mfd.c  |  69 +++++++
 drivers/net/dsa/sja1105/sja1105_mfd.h  |   9 +
 drivers/net/dsa/sja1105/sja1105_spi.c  |   6 -
 8 files changed, 94 insertions(+), 279 deletions(-)
 create mode 100644 drivers/net/dsa/sja1105/sja1105_mfd.c
 create mode 100644 drivers/net/dsa/sja1105/sja1105_mfd.h

diff --git a/drivers/net/dsa/sja1105/Kconfig b/drivers/net/dsa/sja1105/Kconfig
index 1291bba3f3b6..932bca545d69 100644
--- a/drivers/net/dsa/sja1105/Kconfig
+++ b/drivers/net/dsa/sja1105/Kconfig
@@ -7,6 +7,7 @@ tristate "NXP SJA1105 Ethernet switch family support"
 	select PCS_XPCS
 	select PACKING
 	select CRC32
+	select MFD_CORE
 	help
 	  This is the driver for the NXP SJA1105 (5-port) and SJA1110 (10-port)
 	  automotive Ethernet switch family. These are managed over an SPI
diff --git a/drivers/net/dsa/sja1105/Makefile b/drivers/net/dsa/sja1105/Makefile
index 40d69e6c0bae..3ac2d77dbe6c 100644
--- a/drivers/net/dsa/sja1105/Makefile
+++ b/drivers/net/dsa/sja1105/Makefile
@@ -5,6 +5,7 @@ sja1105-objs := \
     sja1105_spi.o \
     sja1105_main.o \
     sja1105_mdio.o \
+    sja1105_mfd.o \
     sja1105_flower.o \
     sja1105_ethtool.o \
     sja1105_devlink.o \
diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h
index 4fd6121bd07f..ff6b69663851 100644
--- a/drivers/net/dsa/sja1105/sja1105.h
+++ b/drivers/net/dsa/sja1105/sja1105.h
@@ -91,8 +91,6 @@ struct sja1105_regs {
 	u64 rmii_ref_clk[SJA1105_MAX_NUM_PORTS];
 	u64 rmii_ext_tx_clk[SJA1105_MAX_NUM_PORTS];
 	u64 stats[__MAX_SJA1105_STATS_AREA][SJA1105_MAX_NUM_PORTS];
-	u64 mdio_100base_tx;
-	u64 mdio_100base_t1;
 	u64 pcs_base[SJA1105_MAX_NUM_PORTS];
 };
 
@@ -279,8 +277,6 @@ struct sja1105_private {
 	struct regmap *regmap;
 	struct devlink_region **regions;
 	struct sja1105_cbs_entry *cbs;
-	struct mii_bus *mdio_base_t1;
-	struct mii_bus *mdio_base_tx;
 	struct mii_bus *mdio_pcs;
 	struct phylink_pcs *pcs[SJA1105_MAX_NUM_PORTS];
 	struct sja1105_ptp_data ptp_data;
diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c
index 622264c13fdb..6da5c655dae7 100644
--- a/drivers/net/dsa/sja1105/sja1105_main.c
+++ b/drivers/net/dsa/sja1105/sja1105_main.c
@@ -23,6 +23,7 @@
 #include <linux/units.h>
 
 #include "sja1105.h"
+#include "sja1105_mfd.h"
 #include "sja1105_tas.h"
 
 #define SJA1105_UNKNOWN_MULTICAST	0x010000000000ull
@@ -3316,6 +3317,11 @@ static int sja1105_probe(struct spi_device *spi)
 	if (priv->max_xfer_len > max_msg - SJA1105_SIZE_SPI_MSG_HEADER)
 		priv->max_xfer_len = max_msg - SJA1105_SIZE_SPI_MSG_HEADER;
 
+	/* Explicitly advertise "no DMA" support, to suppress
+	 * "DMA mask not set" warning in MFD children
+	 */
+	dev->dma_mask = &dev->coherent_dma_mask;
+
 	priv->info = of_device_get_match_data(dev);
 
 	rc = sja1105_create_regmap(priv);
@@ -3356,6 +3362,13 @@ static int sja1105_probe(struct spi_device *spi)
 		return rc;
 	}
 
+	rc = sja1105_mfd_add_devices(ds);
+	if (rc) {
+		dev_err(ds->dev, "Failed to create child devices: %pe\n",
+			ERR_PTR(rc));
+		return rc;
+	}
+
 	if (IS_ENABLED(CONFIG_NET_SCH_CBS)) {
 		priv->cbs = devm_kcalloc(dev, priv->info->num_cbs_shapers,
 					 sizeof(struct sja1105_cbs_entry),
diff --git a/drivers/net/dsa/sja1105/sja1105_mdio.c b/drivers/net/dsa/sja1105/sja1105_mdio.c
index 8d535c033cef..b803ce71f5cc 100644
--- a/drivers/net/dsa/sja1105/sja1105_mdio.c
+++ b/drivers/net/dsa/sja1105/sja1105_mdio.c
@@ -133,238 +133,6 @@ int sja1110_pcs_mdio_write_c45(struct mii_bus *bus, int phy, int mmd, int reg,
 				&tmp, NULL);
 }
 
-enum sja1105_mdio_opcode {
-	SJA1105_C45_ADDR = 0,
-	SJA1105_C22 = 1,
-	SJA1105_C45_DATA = 2,
-	SJA1105_C45_DATA_AUTOINC = 3,
-};
-
-static u64 sja1105_base_t1_encode_addr(struct sja1105_private *priv,
-				       int phy, enum sja1105_mdio_opcode op,
-				       int xad)
-{
-	const struct sja1105_regs *regs = priv->info->regs;
-
-	return regs->mdio_100base_t1 | (phy << 7) | (op << 5) | (xad << 0);
-}
-
-static int sja1105_base_t1_mdio_read_c22(struct mii_bus *bus, int phy, int reg)
-{
-	struct sja1105_mdio_private *mdio_priv = bus->priv;
-	struct sja1105_private *priv = mdio_priv->priv;
-	u64 addr;
-	u32 tmp;
-	int rc;
-
-	addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C22, reg & 0x1f);
-
-	rc = sja1105_xfer_u32(priv, SPI_READ, addr, &tmp, NULL);
-	if (rc < 0)
-		return rc;
-
-	return tmp & 0xffff;
-}
-
-static int sja1105_base_t1_mdio_read_c45(struct mii_bus *bus, int phy,
-					 int mmd, int reg)
-{
-	struct sja1105_mdio_private *mdio_priv = bus->priv;
-	struct sja1105_private *priv = mdio_priv->priv;
-	u64 addr;
-	u32 tmp;
-	int rc;
-
-	addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_ADDR, mmd);
-
-	rc = sja1105_xfer_u32(priv, SPI_WRITE, addr, &reg, NULL);
-	if (rc < 0)
-		return rc;
-
-	addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_DATA, mmd);
-
-	rc = sja1105_xfer_u32(priv, SPI_READ, addr, &tmp, NULL);
-	if (rc < 0)
-		return rc;
-
-	return tmp & 0xffff;
-}
-
-static int sja1105_base_t1_mdio_write_c22(struct mii_bus *bus, int phy, int reg,
-					  u16 val)
-{
-	struct sja1105_mdio_private *mdio_priv = bus->priv;
-	struct sja1105_private *priv = mdio_priv->priv;
-	u64 addr;
-	u32 tmp;
-
-	addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C22, reg & 0x1f);
-
-	tmp = val & 0xffff;
-
-	return sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL);
-}
-
-static int sja1105_base_t1_mdio_write_c45(struct mii_bus *bus, int phy,
-					  int mmd, int reg, u16 val)
-{
-	struct sja1105_mdio_private *mdio_priv = bus->priv;
-	struct sja1105_private *priv = mdio_priv->priv;
-	u64 addr;
-	u32 tmp;
-	int rc;
-
-	addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_ADDR, mmd);
-
-	rc = sja1105_xfer_u32(priv, SPI_WRITE, addr, &reg, NULL);
-	if (rc < 0)
-		return rc;
-
-	addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_DATA, mmd);
-
-	tmp = val & 0xffff;
-
-	return sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL);
-}
-
-static int sja1105_base_tx_mdio_read(struct mii_bus *bus, int phy, int reg)
-{
-	struct sja1105_mdio_private *mdio_priv = bus->priv;
-	struct sja1105_private *priv = mdio_priv->priv;
-	const struct sja1105_regs *regs = priv->info->regs;
-	u32 tmp;
-	int rc;
-
-	rc = sja1105_xfer_u32(priv, SPI_READ, regs->mdio_100base_tx + reg,
-			      &tmp, NULL);
-	if (rc < 0)
-		return rc;
-
-	return tmp & 0xffff;
-}
-
-static int sja1105_base_tx_mdio_write(struct mii_bus *bus, int phy, int reg,
-				      u16 val)
-{
-	struct sja1105_mdio_private *mdio_priv = bus->priv;
-	struct sja1105_private *priv = mdio_priv->priv;
-	const struct sja1105_regs *regs = priv->info->regs;
-	u32 tmp = val;
-
-	return sja1105_xfer_u32(priv, SPI_WRITE, regs->mdio_100base_tx + reg,
-				&tmp, NULL);
-}
-
-static int sja1105_mdiobus_base_tx_register(struct sja1105_private *priv,
-					    struct device_node *mdio_node)
-{
-	struct sja1105_mdio_private *mdio_priv;
-	struct device_node *np;
-	struct mii_bus *bus;
-	int rc = 0;
-
-	np = of_get_compatible_child(mdio_node, "nxp,sja1110-base-tx-mdio");
-	if (!np)
-		return 0;
-
-	if (!of_device_is_available(np))
-		goto out_put_np;
-
-	bus = mdiobus_alloc_size(sizeof(*mdio_priv));
-	if (!bus) {
-		rc = -ENOMEM;
-		goto out_put_np;
-	}
-
-	bus->name = "SJA1110 100base-TX MDIO bus";
-	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-base-tx",
-		 dev_name(priv->ds->dev));
-	bus->read = sja1105_base_tx_mdio_read;
-	bus->write = sja1105_base_tx_mdio_write;
-	bus->parent = priv->ds->dev;
-	mdio_priv = bus->priv;
-	mdio_priv->priv = priv;
-
-	rc = of_mdiobus_register(bus, np);
-	if (rc) {
-		mdiobus_free(bus);
-		goto out_put_np;
-	}
-
-	priv->mdio_base_tx = bus;
-
-out_put_np:
-	of_node_put(np);
-
-	return rc;
-}
-
-static void sja1105_mdiobus_base_tx_unregister(struct sja1105_private *priv)
-{
-	if (!priv->mdio_base_tx)
-		return;
-
-	mdiobus_unregister(priv->mdio_base_tx);
-	mdiobus_free(priv->mdio_base_tx);
-	priv->mdio_base_tx = NULL;
-}
-
-static int sja1105_mdiobus_base_t1_register(struct sja1105_private *priv,
-					    struct device_node *mdio_node)
-{
-	struct sja1105_mdio_private *mdio_priv;
-	struct device_node *np;
-	struct mii_bus *bus;
-	int rc = 0;
-
-	np = of_get_compatible_child(mdio_node, "nxp,sja1110-base-t1-mdio");
-	if (!np)
-		return 0;
-
-	if (!of_device_is_available(np))
-		goto out_put_np;
-
-	bus = mdiobus_alloc_size(sizeof(*mdio_priv));
-	if (!bus) {
-		rc = -ENOMEM;
-		goto out_put_np;
-	}
-
-	bus->name = "SJA1110 100base-T1 MDIO bus";
-	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-base-t1",
-		 dev_name(priv->ds->dev));
-	bus->read = sja1105_base_t1_mdio_read_c22;
-	bus->write = sja1105_base_t1_mdio_write_c22;
-	bus->read_c45 = sja1105_base_t1_mdio_read_c45;
-	bus->write_c45 = sja1105_base_t1_mdio_write_c45;
-	bus->parent = priv->ds->dev;
-	mdio_priv = bus->priv;
-	mdio_priv->priv = priv;
-
-	rc = of_mdiobus_register(bus, np);
-	if (rc) {
-		mdiobus_free(bus);
-		goto out_put_np;
-	}
-
-	priv->mdio_base_t1 = bus;
-
-out_put_np:
-	of_node_put(np);
-
-	return rc;
-}
-
-static void sja1105_mdiobus_base_t1_unregister(struct sja1105_private *priv)
-{
-	if (!priv->mdio_base_t1)
-		return;
-
-	mdiobus_unregister(priv->mdio_base_t1);
-	mdiobus_free(priv->mdio_base_t1);
-	priv->mdio_base_t1 = NULL;
-}
-
 static int sja1105_mdiobus_pcs_register(struct sja1105_private *priv)
 {
 	struct sja1105_mdio_private *mdio_priv;
@@ -459,49 +227,13 @@ static void sja1105_mdiobus_pcs_unregister(struct sja1105_private *priv)
 int sja1105_mdiobus_register(struct dsa_switch *ds)
 {
 	struct sja1105_private *priv = ds->priv;
-	const struct sja1105_regs *regs = priv->info->regs;
-	struct device_node *switch_node = ds->dev->of_node;
-	struct device_node *mdio_node;
-	int rc;
-
-	rc = sja1105_mdiobus_pcs_register(priv);
-	if (rc)
-		return rc;
-
-	mdio_node = of_get_available_child_by_name(switch_node, "mdios");
-	if (!mdio_node)
-		return 0;
 
-	if (regs->mdio_100base_tx != SJA1105_RSV_ADDR) {
-		rc = sja1105_mdiobus_base_tx_register(priv, mdio_node);
-		if (rc)
-			goto err_put_mdio_node;
-	}
-
-	if (regs->mdio_100base_t1 != SJA1105_RSV_ADDR) {
-		rc = sja1105_mdiobus_base_t1_register(priv, mdio_node);
-		if (rc)
-			goto err_free_base_tx_mdiobus;
-	}
-
-	of_node_put(mdio_node);
-
-	return 0;
-
-err_free_base_tx_mdiobus:
-	sja1105_mdiobus_base_tx_unregister(priv);
-err_put_mdio_node:
-	of_node_put(mdio_node);
-	sja1105_mdiobus_pcs_unregister(priv);
-
-	return rc;
+	return sja1105_mdiobus_pcs_register(priv);
 }
 
 void sja1105_mdiobus_unregister(struct dsa_switch *ds)
 {
 	struct sja1105_private *priv = ds->priv;
 
-	sja1105_mdiobus_base_t1_unregister(priv);
-	sja1105_mdiobus_base_tx_unregister(priv);
 	sja1105_mdiobus_pcs_unregister(priv);
 }
diff --git a/drivers/net/dsa/sja1105/sja1105_mfd.c b/drivers/net/dsa/sja1105/sja1105_mfd.c
new file mode 100644
index 000000000000..9e60cd3b5d01
--- /dev/null
+++ b/drivers/net/dsa/sja1105/sja1105_mfd.c
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright 2025 NXP
+ */
+#include <linux/ioport.h>
+#include <linux/mfd/core.h>
+
+#include "sja1105.h"
+#include "sja1105_mfd.h"
+
+static const struct resource sja1110_mdio_cbtx_res =
+	DEFINE_RES_REG_NAMED(0x709000, 0x1000, "mdio_cbtx");
+
+static const struct resource sja1110_mdio_cbt1_res =
+	DEFINE_RES_REG_NAMED(0x704000, 0x4000, "mdio_cbt1");
+
+static void sja1105_mfd_add_mdio_cells(struct sja1105_private *priv,
+				       struct device_node *mdio_node,
+				       struct mfd_cell *cells,
+				       int *num_cells)
+{
+	struct device_node *np;
+
+	np = of_get_compatible_child(mdio_node, "nxp,sja1110-base-tx-mdio");
+	if (np && of_device_is_available(np)) {
+		cells[(*num_cells)++] = (struct mfd_cell) {
+			.name = "sja1110-base-tx-mdio",
+			.of_compatible = "nxp,sja1110-base-tx-mdio",
+			.resources = &sja1110_mdio_cbtx_res,
+			.num_resources = 1,
+			.parent_of_node = mdio_node,
+		};
+	}
+	if (np)
+		of_node_put(np);
+
+	np = of_get_compatible_child(mdio_node, "nxp,sja1110-base-t1-mdio");
+	if (np && of_device_is_available(np)) {
+		cells[(*num_cells)++] = (struct mfd_cell) {
+			.name = "sja1110-base-t1-mdio",
+			.of_compatible = "nxp,sja1110-base-t1-mdio",
+			.resources = &sja1110_mdio_cbt1_res,
+			.num_resources = 1,
+			.parent_of_node = mdio_node,
+		};
+	}
+	if (np)
+		of_node_put(np);
+}
+
+int sja1105_mfd_add_devices(struct dsa_switch *ds)
+{
+	struct device_node *switch_node = dev_of_node(ds->dev);
+	struct sja1105_private *priv = ds->priv;
+	struct device_node *mdio_node;
+	struct mfd_cell cells[2] = {};
+	int num_cells = 0;
+	int rc = 0;
+
+	mdio_node = of_get_available_child_by_name(switch_node, "mdios");
+	if (mdio_node)
+		sja1105_mfd_add_mdio_cells(priv, mdio_node, cells, &num_cells);
+
+	if (num_cells > 0)
+		rc = devm_mfd_add_devices(ds->dev, PLATFORM_DEVID_AUTO, cells,
+					  num_cells, NULL, 0, NULL);
+
+	of_node_put(mdio_node);
+	return rc;
+}
diff --git a/drivers/net/dsa/sja1105/sja1105_mfd.h b/drivers/net/dsa/sja1105/sja1105_mfd.h
new file mode 100644
index 000000000000..c33c8ff24e25
--- /dev/null
+++ b/drivers/net/dsa/sja1105/sja1105_mfd.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright 2025 NXP
+ */
+#ifndef _SJA1105_MFD_H
+#define _SJA1105_MFD_H
+
+int sja1105_mfd_add_devices(struct dsa_switch *ds);
+
+#endif
diff --git a/drivers/net/dsa/sja1105/sja1105_spi.c b/drivers/net/dsa/sja1105/sja1105_spi.c
index cfc76af8a65b..087acded7827 100644
--- a/drivers/net/dsa/sja1105/sja1105_spi.c
+++ b/drivers/net/dsa/sja1105/sja1105_spi.c
@@ -498,8 +498,6 @@ static const struct sja1105_regs sja1105et_regs = {
 	.ptpclkval = 0x18, /* Spans 0x18 to 0x19 */
 	.ptpclkrate = 0x1A,
 	.ptpclkcorp = 0x1D,
-	.mdio_100base_tx = SJA1105_RSV_ADDR,
-	.mdio_100base_t1 = SJA1105_RSV_ADDR,
 };
 
 static const struct sja1105_regs sja1105pqrs_regs = {
@@ -537,8 +535,6 @@ static const struct sja1105_regs sja1105pqrs_regs = {
 	.ptpclkrate = 0x1B,
 	.ptpclkcorp = 0x1E,
 	.ptpsyncts = 0x1F,
-	.mdio_100base_tx = SJA1105_RSV_ADDR,
-	.mdio_100base_t1 = SJA1105_RSV_ADDR,
 };
 
 static const struct sja1105_regs sja1110_regs = {
@@ -621,8 +617,6 @@ static const struct sja1105_regs sja1110_regs = {
 	.ptpclkrate = SJA1110_SPI_ADDR(0x74),
 	.ptpclkcorp = SJA1110_SPI_ADDR(0x80),
 	.ptpsyncts = SJA1110_SPI_ADDR(0x84),
-	.mdio_100base_tx = 0x1c2400,
-	.mdio_100base_t1 = 0x1c1000,
 	.pcs_base = {SJA1105_RSV_ADDR, 0x1c1400, 0x1c1800, 0x1c1c00, 0x1c2000,
 		     SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
 		     SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR},
-- 
2.34.1
Re: [PATCH net-next 08/15] net: dsa: sja1105: transition OF-based MDIO drivers to standalone
Posted by Lee Jones 1 week, 4 days ago
On Tue, 18 Nov 2025, Vladimir Oltean wrote:

> Delete the duplicated drivers for 100base-T1 and 100base-TX from the DSA
> driver, and use devm_mfd_add_devices() to platform devices which probe
> on the dedicated drivers from drivers/net/mdio/. This makes the switch
> act as a sort of bus driver for devices in the "mdios" subnode.
> 
> We can use mfd because the switch driver interacts with the PHYs from
> these MDIO buses exclusively using phylink, which follows "phy-handle"
> fwnode references to them.
> 
> Cc: Lee Jones <lee@kernel.org>
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
> ---
>  drivers/net/dsa/sja1105/Kconfig        |   1 +
>  drivers/net/dsa/sja1105/Makefile       |   1 +
>  drivers/net/dsa/sja1105/sja1105.h      |   4 -
>  drivers/net/dsa/sja1105/sja1105_main.c |  13 ++
>  drivers/net/dsa/sja1105/sja1105_mdio.c | 270 +------------------------
>  drivers/net/dsa/sja1105/sja1105_mfd.c  |  69 +++++++
>  drivers/net/dsa/sja1105/sja1105_mfd.h  |   9 +
>  drivers/net/dsa/sja1105/sja1105_spi.c  |   6 -
>  8 files changed, 94 insertions(+), 279 deletions(-)
>  create mode 100644 drivers/net/dsa/sja1105/sja1105_mfd.c
>  create mode 100644 drivers/net/dsa/sja1105/sja1105_mfd.h
> 
> diff --git a/drivers/net/dsa/sja1105/Kconfig b/drivers/net/dsa/sja1105/Kconfig
> index 1291bba3f3b6..932bca545d69 100644
> --- a/drivers/net/dsa/sja1105/Kconfig
> +++ b/drivers/net/dsa/sja1105/Kconfig
> @@ -7,6 +7,7 @@ tristate "NXP SJA1105 Ethernet switch family support"
>  	select PCS_XPCS
>  	select PACKING
>  	select CRC32
> +	select MFD_CORE
>  	help
>  	  This is the driver for the NXP SJA1105 (5-port) and SJA1110 (10-port)
>  	  automotive Ethernet switch family. These are managed over an SPI
> diff --git a/drivers/net/dsa/sja1105/Makefile b/drivers/net/dsa/sja1105/Makefile
> index 40d69e6c0bae..3ac2d77dbe6c 100644
> --- a/drivers/net/dsa/sja1105/Makefile
> +++ b/drivers/net/dsa/sja1105/Makefile
> @@ -5,6 +5,7 @@ sja1105-objs := \
>      sja1105_spi.o \
>      sja1105_main.o \
>      sja1105_mdio.o \
> +    sja1105_mfd.o \
>      sja1105_flower.o \
>      sja1105_ethtool.o \
>      sja1105_devlink.o \
> diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h
> index 4fd6121bd07f..ff6b69663851 100644
> --- a/drivers/net/dsa/sja1105/sja1105.h
> +++ b/drivers/net/dsa/sja1105/sja1105.h
> @@ -91,8 +91,6 @@ struct sja1105_regs {
>  	u64 rmii_ref_clk[SJA1105_MAX_NUM_PORTS];
>  	u64 rmii_ext_tx_clk[SJA1105_MAX_NUM_PORTS];
>  	u64 stats[__MAX_SJA1105_STATS_AREA][SJA1105_MAX_NUM_PORTS];
> -	u64 mdio_100base_tx;
> -	u64 mdio_100base_t1;
>  	u64 pcs_base[SJA1105_MAX_NUM_PORTS];
>  };
>  
> @@ -279,8 +277,6 @@ struct sja1105_private {
>  	struct regmap *regmap;
>  	struct devlink_region **regions;
>  	struct sja1105_cbs_entry *cbs;
> -	struct mii_bus *mdio_base_t1;
> -	struct mii_bus *mdio_base_tx;
>  	struct mii_bus *mdio_pcs;
>  	struct phylink_pcs *pcs[SJA1105_MAX_NUM_PORTS];
>  	struct sja1105_ptp_data ptp_data;
> diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c
> index 622264c13fdb..6da5c655dae7 100644
> --- a/drivers/net/dsa/sja1105/sja1105_main.c
> +++ b/drivers/net/dsa/sja1105/sja1105_main.c
> @@ -23,6 +23,7 @@
>  #include <linux/units.h>
>  
>  #include "sja1105.h"
> +#include "sja1105_mfd.h"
>  #include "sja1105_tas.h"
>  
>  #define SJA1105_UNKNOWN_MULTICAST	0x010000000000ull
> @@ -3316,6 +3317,11 @@ static int sja1105_probe(struct spi_device *spi)
>  	if (priv->max_xfer_len > max_msg - SJA1105_SIZE_SPI_MSG_HEADER)
>  		priv->max_xfer_len = max_msg - SJA1105_SIZE_SPI_MSG_HEADER;
>  
> +	/* Explicitly advertise "no DMA" support, to suppress
> +	 * "DMA mask not set" warning in MFD children
> +	 */
> +	dev->dma_mask = &dev->coherent_dma_mask;
> +
>  	priv->info = of_device_get_match_data(dev);
>  
>  	rc = sja1105_create_regmap(priv);
> @@ -3356,6 +3362,13 @@ static int sja1105_probe(struct spi_device *spi)
>  		return rc;
>  	}
>  
> +	rc = sja1105_mfd_add_devices(ds);
> +	if (rc) {
> +		dev_err(ds->dev, "Failed to create child devices: %pe\n",
> +			ERR_PTR(rc));
> +		return rc;
> +	}
> +
>  	if (IS_ENABLED(CONFIG_NET_SCH_CBS)) {
>  		priv->cbs = devm_kcalloc(dev, priv->info->num_cbs_shapers,
>  					 sizeof(struct sja1105_cbs_entry),
> diff --git a/drivers/net/dsa/sja1105/sja1105_mdio.c b/drivers/net/dsa/sja1105/sja1105_mdio.c
> index 8d535c033cef..b803ce71f5cc 100644
> --- a/drivers/net/dsa/sja1105/sja1105_mdio.c
> +++ b/drivers/net/dsa/sja1105/sja1105_mdio.c
> @@ -133,238 +133,6 @@ int sja1110_pcs_mdio_write_c45(struct mii_bus *bus, int phy, int mmd, int reg,
>  				&tmp, NULL);

[...]

> diff --git a/drivers/net/dsa/sja1105/sja1105_mfd.c b/drivers/net/dsa/sja1105/sja1105_mfd.c
> new file mode 100644
> index 000000000000..9e60cd3b5d01
> --- /dev/null
> +++ b/drivers/net/dsa/sja1105/sja1105_mfd.c
> @@ -0,0 +1,69 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Copyright 2025 NXP
> + */
> +#include <linux/ioport.h>
> +#include <linux/mfd/core.h>

The MFD API is not to be {ab}used out side of drivers/mfd.

Maybe of_platform_populate() will scratch your itch instead.

[...]

-- 
Lee Jones [李琼斯]
Re: [PATCH net-next 08/15] net: dsa: sja1105: transition OF-based MDIO drivers to standalone
Posted by Vladimir Oltean 1 week, 4 days ago
Hi Lee,

Thank you for commenting on the patch!

On Thu, Nov 20, 2025 at 02:40:46PM +0000, Lee Jones wrote:
> The MFD API is not to be {ab}used out side of drivers/mfd.

If mfd_add_devices() is not to be used outside of drivers/mfd, why
export it to the global include/linux/mfd/core.h in the first place,
rather than make the header available just to drivers/mfd?

> Maybe of_platform_populate() will scratch your itch instead.

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.

I'm not trying to start an argument, but as you can see, I've been stuck
on this problem for years, and I'm between a rock and a hard place.
Re: [PATCH net-next 08/15] net: dsa: sja1105: transition OF-based MDIO drivers to standalone
Posted by Lee Jones 1 week, 4 days ago
On Thu, 20 Nov 2025, Vladimir Oltean wrote:

> Hi Lee,
> 
> Thank you for commenting on the patch!
> 
> On Thu, Nov 20, 2025 at 02:40:46PM +0000, Lee Jones wrote:
> > The MFD API is not to be {ab}used out side of drivers/mfd.
> 
> If mfd_add_devices() is not to be used outside of drivers/mfd, why
> export it to the global include/linux/mfd/core.h in the first place,
> rather than make the header available just to drivers/mfd?

That's a good question.

mfd_add_devices() has been exported since its inception nearly 20 years
ago.  But it wasn't {ab}used outside of the subsystem until 2011 when it
somehow found its way into the NVEC Staging driver and then into some
IIO driver in 2015, etc.  Since then other 8 instances have slipped
through the gaps without me noticing.  I'd love to remove the global
export, but something would need to be done about those 10 occurrences
before hand and I just don't have the time to invest in that right now.

> > Maybe of_platform_populate() will scratch your itch instead.
> 
> 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.
> 
> I'm not trying to start an argument, but as you can see, I've been stuck
> on this problem for years, and I'm between a rock and a hard place.

I get that.  Equally, I'm not trying to be suborn, but those are the
rule's I've been attempting to stick to for the last decade and a bit to
prevent (minor) chaos.

The canonical answer goes 3 ways: If you want to use the MFD API, move
the handling to drivers/mfd.  If it's possible, use one of the
predetermined helpers like of_platform_populate() (and I think we
authored another one that worked around some of its issues, but I forget
where we put it!).  Or if all else fails, you have to register the
device the old fashioned way with the platform_device_*() API.

-- 
Lee Jones [李琼斯]
Re: [PATCH net-next 08/15] net: dsa: sja1105: transition OF-based MDIO drivers to standalone
Posted by Vladimir Oltean 1 week, 4 days ago
On Thu, Nov 20, 2025 at 04:36:03PM +0000, Lee Jones wrote:
> The canonical answer goes 3 ways: If you want to use the MFD API, move
> the handling to drivers/mfd.

Wait, so now it's negotiable? What about "this device is not an MFD"
from the other patch? Move it to another folder and suddenly it's an MFD?
https://lore.kernel.org/netdev/20251120153622.p6sy77coa3de6srw@skbuf/

> If it's possible, use one of the predetermined helpers like
> of_platform_populate() (and I think we authored another one that
> worked around some of its issues, but I forget where we put it!).

yay...

I don't need the code necessarily, just the overall idea if you remember it.

> Or if all else fails, you have to register the device the old
> fashioned way with the platform_device_*() API.

Do you realize that by this, you are inviting me to waste time until the
next reviewer rightfully asks, why didn't you use MFD, then I'll point
them towards this discussion, but you didn't really answer?
Re: [PATCH net-next 08/15] net: dsa: sja1105: transition OF-based MDIO drivers to standalone
Posted by Lee Jones 1 week, 3 days ago
On Thu, 20 Nov 2025, Vladimir Oltean wrote:

> On Thu, Nov 20, 2025 at 04:36:03PM +0000, Lee Jones wrote:
> > The canonical answer goes 3 ways: If you want to use the MFD API, move
> > the handling to drivers/mfd.
> 
> Wait, so now it's negotiable? What about "this device is not an MFD"
> from the other patch? Move it to another folder and suddenly it's an MFD?
> https://lore.kernel.org/netdev/20251120153622.p6sy77coa3de6srw@skbuf/

The "canonical answer" is the general answer, the one that applies to
everyone, not just your use-case.  I'm not (yet?) convinced that this is
an MFD, so at the moment, option one is not on the table for you.

> > If it's possible, use one of the predetermined helpers like
> > of_platform_populate() (and I think we authored another one that
> > worked around some of its issues, but I forget where we put it!).
> 
> yay...
> 
> I don't need the code necessarily, just the overall idea if you remember it.

It was an extension to "simple-bus".  Perhaps "simple-mfd"?

Again, it might not work for you, but it's an avenue worth exploring.

> > Or if all else fails, you have to register the device the old
> > fashioned way with the platform_device_*() API.
> 
> Do you realize that by this, you are inviting me to waste time until the
> next reviewer rightfully asks, why didn't you use MFD, then I'll point
> them towards this discussion, but you didn't really answer?

This is still an abuse of the MFD API.  Used outside of the subsystem
for something that isn't an MFD.  I like the idea of not duplicating
code, but the fact remains that this is a hack.

Another more recent avenue you may explore is the Auxiliary Bus.

-- 
Lee Jones [李琼斯]