Commit c5e4ddbd authored by Chen-Yu Tsai's avatar Chen-Yu Tsai Committed by David S. Miller

net: stmmac: Add support for optional reset control

The DWMAC has a reset assert line, which is used on some SoCs. Add an
optional reset control to stmmac driver core.

To support reset control deferred probing, this patch changes the driver
probe function to return the actual error, instead of just -EINVAL.
Signed-off-by: default avatarChen-Yu Tsai <wens@csie.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 62866e98
...@@ -30,6 +30,9 @@ Required properties: ...@@ -30,6 +30,9 @@ Required properties:
Optional properties: Optional properties:
- mac-address: 6 bytes, mac address - mac-address: 6 bytes, mac address
- resets: Should contain a phandle to the STMMAC reset signal, if any
- reset-names: Should contain the reset signal name "stmmaceth", if a
reset phandle is given
Examples: Examples:
......
...@@ -5,6 +5,7 @@ config STMMAC_ETH ...@@ -5,6 +5,7 @@ config STMMAC_ETH
select PHYLIB select PHYLIB
select CRC32 select CRC32
select PTP_1588_CLOCK select PTP_1588_CLOCK
select RESET_CONTROLLER
---help--- ---help---
This is the driver for the Ethernet IPs are built around a This is the driver for the Ethernet IPs are built around a
Synopsys IP Core and only tested on the STMicroelectronics Synopsys IP Core and only tested on the STMicroelectronics
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <linux/pci.h> #include <linux/pci.h>
#include "common.h" #include "common.h"
#include <linux/ptp_clock_kernel.h> #include <linux/ptp_clock_kernel.h>
#include <linux/reset.h>
struct stmmac_priv { struct stmmac_priv {
/* Frequently used values are kept adjacent for cache effect */ /* Frequently used values are kept adjacent for cache effect */
...@@ -91,6 +92,7 @@ struct stmmac_priv { ...@@ -91,6 +92,7 @@ struct stmmac_priv {
int wolopts; int wolopts;
int wol_irq; int wol_irq;
struct clk *stmmac_clk; struct clk *stmmac_clk;
struct reset_control *stmmac_rst;
int clk_csr; int clk_csr;
struct timer_list eee_ctrl_timer; struct timer_list eee_ctrl_timer;
int lpi_irq; int lpi_irq;
......
...@@ -51,6 +51,7 @@ ...@@ -51,6 +51,7 @@
#include <linux/net_tstamp.h> #include <linux/net_tstamp.h>
#include "stmmac_ptp.h" #include "stmmac_ptp.h"
#include "stmmac.h" #include "stmmac.h"
#include <linux/reset.h>
#define STMMAC_ALIGN(x) L1_CACHE_ALIGN(x) #define STMMAC_ALIGN(x) L1_CACHE_ALIGN(x)
#define JUMBO_LEN 9000 #define JUMBO_LEN 9000
...@@ -2728,10 +2729,24 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device, ...@@ -2728,10 +2729,24 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
if (IS_ERR(priv->stmmac_clk)) { if (IS_ERR(priv->stmmac_clk)) {
dev_warn(priv->device, "%s: warning: cannot get CSR clock\n", dev_warn(priv->device, "%s: warning: cannot get CSR clock\n",
__func__); __func__);
ret = PTR_ERR(priv->stmmac_clk);
goto error_clk_get; goto error_clk_get;
} }
clk_prepare_enable(priv->stmmac_clk); clk_prepare_enable(priv->stmmac_clk);
priv->stmmac_rst = devm_reset_control_get(priv->device,
STMMAC_RESOURCE_NAME);
if (IS_ERR(priv->stmmac_rst)) {
if (PTR_ERR(priv->stmmac_rst) == -EPROBE_DEFER) {
ret = -EPROBE_DEFER;
goto error_hw_init;
}
dev_info(priv->device, "no reset control found\n");
priv->stmmac_rst = NULL;
}
if (priv->stmmac_rst)
reset_control_deassert(priv->stmmac_rst);
/* Init MAC and get the capabilities */ /* Init MAC and get the capabilities */
ret = stmmac_hw_init(priv); ret = stmmac_hw_init(priv);
if (ret) if (ret)
...@@ -2808,7 +2823,7 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device, ...@@ -2808,7 +2823,7 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
error_clk_get: error_clk_get:
free_netdev(ndev); free_netdev(ndev);
return NULL; return ERR_PTR(ret);
} }
/** /**
...@@ -2832,6 +2847,8 @@ int stmmac_dvr_remove(struct net_device *ndev) ...@@ -2832,6 +2847,8 @@ int stmmac_dvr_remove(struct net_device *ndev)
stmmac_mdio_unregister(ndev); stmmac_mdio_unregister(ndev);
netif_carrier_off(ndev); netif_carrier_off(ndev);
unregister_netdev(ndev); unregister_netdev(ndev);
if (priv->stmmac_rst)
reset_control_assert(priv->stmmac_rst);
clk_disable_unprepare(priv->stmmac_clk); clk_disable_unprepare(priv->stmmac_clk);
free_netdev(ndev); free_netdev(ndev);
......
...@@ -100,9 +100,9 @@ static int stmmac_pci_probe(struct pci_dev *pdev, ...@@ -100,9 +100,9 @@ static int stmmac_pci_probe(struct pci_dev *pdev,
stmmac_default_data(); stmmac_default_data();
priv = stmmac_dvr_probe(&(pdev->dev), &plat_dat, addr); priv = stmmac_dvr_probe(&(pdev->dev), &plat_dat, addr);
if (!priv) { if (IS_ERR(priv)) {
pr_err("%s: main driver probe failed", __func__); pr_err("%s: main driver probe failed", __func__);
ret = -ENODEV; ret = PTR_ERR(priv);
goto err_out; goto err_out;
} }
priv->dev->irq = pdev->irq; priv->dev->irq = pdev->irq;
......
...@@ -152,9 +152,9 @@ static int stmmac_pltfr_probe(struct platform_device *pdev) ...@@ -152,9 +152,9 @@ static int stmmac_pltfr_probe(struct platform_device *pdev)
} }
priv = stmmac_dvr_probe(&(pdev->dev), plat_dat, addr); priv = stmmac_dvr_probe(&(pdev->dev), plat_dat, addr);
if (!priv) { if (IS_ERR(priv)) {
pr_err("%s: main driver probe failed", __func__); pr_err("%s: main driver probe failed", __func__);
return -ENODEV; return PTR_ERR(priv);
} }
/* Get MAC address if available (DT) */ /* Get MAC address if available (DT) */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment