diff --git a/Documentation/devicetree/bindings/net/microchip,lan8650.yaml b/Documentation/devicetree/bindings/net/microchip,lan8650.yaml index 766ff58147ae..1b543ce30763 100644 --- a/Documentation/devicetree/bindings/net/microchip,lan8650.yaml +++ b/Documentation/devicetree/bindings/net/microchip,lan8650.yaml @@ -40,6 +40,11 @@ properties: Event. maxItems: 1 + reset-gpios: + description: + GPIO connected to the active-low RESET_N pin of the MAC-PHY. + maxItems: 1 + spi-max-frequency: minimum: 15000000 maximum: 25000000 diff --git a/drivers/net/ethernet/adi/adin1140.c b/drivers/net/ethernet/adi/adin1140.c index 93710baca151..adc6e2ef44f8 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 26a2761332a5..127afb9e9f14 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 6fcc5f561d56..364027c39fa4 100644 --- a/drivers/net/ethernet/oa_tc6.c +++ b/drivers/net/ethernet/oa_tc6.c @@ -6,6 +6,8 @@ */ #include +#include +#include #include #include #include @@ -88,6 +90,7 @@ struct oa_tc6 { bool disable_traffic; bool prot_ctrl; enum oa_tc6_quirk_flag quirk_flags; + struct gpio_desc *reset_gpio; }; enum oa_tc6_header_type { @@ -1453,7 +1456,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 +1466,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 +1479,77 @@ 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); + + tc6->reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(tc6->reset_gpio)) + return ERR_PTR(dev_err_probe(&spi->dev, + PTR_ERR(tc6->reset_gpio), + "failed to get reset gpio\n")); + + if (tc6->reset_gpio) { + /* Keep the reset asserted for 10 us and then allow 1 ms of + * settle time for the crystal oscillator startup. + */ + fsleep(10); + gpiod_set_value_cansleep(tc6->reset_gpio, 0); + fsleep(1000); + } /* 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 +1590,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);