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

Vladimir Oltean
2025-11-18T19:06:05Z

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