[PATCH net-next v3 3/4] net: ethernet: oa_tc6: return ERR_PTR from oa_tc6_init()

From: Alessandro Zini

Date: Fri Sep 18 2026 - 18:50:45 EST


oa_tc6_init() returns NULL on failure, so the reason for the failure is
lost and both callers turn it into a plain -ENODEV. In preparation for
acquiring an optional reset GPIO, which can return -EPROBE_DEFER when the
GPIO provider is not available yet, the error code has to reach the driver
core, otherwise the SPI device would never be probed again.

Convert oa_tc6_init() to return an ERR_PTR on failure instead of NULL,
and update the lan865x and adin1140 callers to check with IS_ERR() and
propagate the error with PTR_ERR().

Signed-off-by: Alessandro Zini <alessandro.zini@xxxxxxxxxxx>
---
Changes in v3:
- New patch to allow proper propagation of error codes, such as
-EPROBE_DEFER
drivers/net/ethernet/adi/adin1140.c | 4 +--
.../net/ethernet/microchip/lan865x/lan865x.c | 4 +--
drivers/net/ethernet/oa_tc6.c | 27 ++++++++++---------
3 files changed, 18 insertions(+), 17 deletions(-)

diff --git a/drivers/net/ethernet/adi/adin1140.c b/drivers/net/ethernet/adi/adin1140.c
index 93710baca1517..adc6e2ef44f8c 100644
--- a/drivers/net/ethernet/adi/adin1140.c
+++ b/drivers/net/ethernet/adi/adin1140.c
@@ -725,8 +725,8 @@ static int adin1140_probe(struct spi_device *spi)
tc6_quirks.quirk_flags = OA_TC6_BROKEN_PHY;

priv->tc6 = oa_tc6_init(spi, netdev, &tc6_quirks);
- if (!priv->tc6)
- return -ENODEV;
+ if (IS_ERR(priv->tc6))
+ return PTR_ERR(priv->tc6);

ret = devm_add_action_or_reset(&spi->dev, adin1140_oa_tc6_remove,
priv->tc6);
diff --git a/drivers/net/ethernet/microchip/lan865x/lan865x.c b/drivers/net/ethernet/microchip/lan865x/lan865x.c
index 26a2761332a5a..127afb9e9f141 100644
--- a/drivers/net/ethernet/microchip/lan865x/lan865x.c
+++ b/drivers/net/ethernet/microchip/lan865x/lan865x.c
@@ -347,8 +347,8 @@ static int lan865x_probe(struct spi_device *spi)
INIT_WORK(&priv->multicast_work, lan865x_multicast_work_handler);

priv->tc6 = oa_tc6_init(spi, netdev, NULL);
- if (!priv->tc6) {
- ret = -ENODEV;
+ if (IS_ERR(priv->tc6)) {
+ ret = PTR_ERR(priv->tc6);
goto free_netdev;
}

diff --git a/drivers/net/ethernet/oa_tc6.c b/drivers/net/ethernet/oa_tc6.c
index 6fcc5f561d560..8c82bc8354ede 100644
--- a/drivers/net/ethernet/oa_tc6.c
+++ b/drivers/net/ethernet/oa_tc6.c
@@ -1453,7 +1453,7 @@ static int oa_tc6_check_ctrl_protection(struct oa_tc6 *tc6)
* @quirks: device specific modifiers for the OA TC6 protocol.
*
* Return: pointer reference to the oa_tc6 structure if the MAC-PHY
- * initialization is successful otherwise NULL.
+ * initialization is successful otherwise an ERR_PTR.
*/
struct oa_tc6 *oa_tc6_init(struct spi_device *spi, struct net_device *netdev,
struct oa_tc6_quirks *quirks)
@@ -1463,7 +1463,7 @@ struct oa_tc6 *oa_tc6_init(struct spi_device *spi, struct net_device *netdev,

tc6 = devm_kzalloc(&spi->dev, sizeof(*tc6), GFP_KERNEL);
if (!tc6)
- return NULL;
+ return ERR_PTR(-ENOMEM);

tc6->spi = spi;
tc6->netdev = netdev;
@@ -1476,60 +1476,61 @@ struct oa_tc6 *oa_tc6_init(struct spi_device *spi, struct net_device *netdev,

/* Set the SPI controller to pump at realtime priority */
tc6->spi->rt = true;
- if (spi_setup(tc6->spi) < 0)
- return NULL;
+ ret = spi_setup(tc6->spi);
+ if (ret < 0)
+ return ERR_PTR(ret);

tc6->spi_ctrl_tx_buf = devm_kzalloc(&tc6->spi->dev,
OA_TC6_CTRL_SPI_BUF_SIZE,
GFP_KERNEL);
if (!tc6->spi_ctrl_tx_buf)
- return NULL;
+ return ERR_PTR(-ENOMEM);

tc6->spi_ctrl_rx_buf = devm_kzalloc(&tc6->spi->dev,
OA_TC6_CTRL_SPI_BUF_SIZE,
GFP_KERNEL);
if (!tc6->spi_ctrl_rx_buf)
- return NULL;
+ return ERR_PTR(-ENOMEM);

tc6->spi_data_tx_buf = devm_kzalloc(&tc6->spi->dev,
OA_TC6_SPI_DATA_BUF_SIZE,
GFP_KERNEL);
if (!tc6->spi_data_tx_buf)
- return NULL;
+ return ERR_PTR(-ENOMEM);

tc6->spi_data_rx_buf = devm_kzalloc(&tc6->spi->dev,
OA_TC6_SPI_DATA_BUF_SIZE,
GFP_KERNEL);
if (!tc6->spi_data_rx_buf)
- return NULL;
+ return ERR_PTR(-ENOMEM);

/* Check the PROTE bit status so that we can reset the device */
ret = oa_tc6_check_ctrl_protection(tc6);
if (ret) {
dev_err(&tc6->spi->dev,
"Failed to check the protection mode: %d\n", ret);
- return NULL;
+ return ERR_PTR(ret);
}

ret = oa_tc6_sw_reset_macphy(tc6);
if (ret) {
dev_err(&tc6->spi->dev,
"MAC-PHY software reset failed: %d\n", ret);
- return NULL;
+ return ERR_PTR(ret);
}

ret = oa_tc6_unmask_macphy_error_interrupts(tc6);
if (ret) {
dev_err(&tc6->spi->dev,
"MAC-PHY error interrupts unmask failed: %d\n", ret);
- return NULL;
+ return ERR_PTR(ret);
}

ret = oa_tc6_phy_init(tc6);
if (ret) {
dev_err(&tc6->spi->dev,
"MAC internal PHY initialization failed: %d\n", ret);
- return NULL;
+ return ERR_PTR(ret);
}

ret = oa_tc6_enable_data_transfer(tc6);
@@ -1570,7 +1571,7 @@ struct oa_tc6 *oa_tc6_init(struct spi_device *spi, struct net_device *netdev,

phy_exit:
oa_tc6_phy_exit(tc6);
- return NULL;
+ return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(oa_tc6_init);

--
2.55.0