From: Josep Orga Date: Sat, 18 Apr 2020 11:33:39 +0000 (+0200) Subject: net: ethernet: fec_main: Add "phy-reset-in-suspend" device tree option. When this... X-Git-Tag: rel_imx_4.19.35_1.1.0-somdevices.0~32 X-Git-Url: https://git.somdevices.com/?a=commitdiff_plain;h=06f023d1295f74bf55e2473e9881cd191666b4de;p=linux.git net: ethernet: fec_main: Add "phy-reset-in-suspend" device tree option. When this option is present, the driver will assert the phy reset line during suspend. There are two main reasons to set this configuration: - Avoid that the phy reset line "powers" the phy when the phy power is turned off. - Ensure that the phy is reset when waking up from suspend, what helps to ensure proper operation when the phy power is turned off. Based on: https://github.com/digi-embedded/linux/commit/f0ddbc0153b269bfd21b84dbd4ad16acdfd21f29 Signed-off-by: Josep Orga --- diff --git a/Documentation/devicetree/bindings/net/fsl-fec.txt b/Documentation/devicetree/bindings/net/fsl-fec.txt index 87f570dd98c1..051a22358a29 100644 --- a/Documentation/devicetree/bindings/net/fsl-fec.txt +++ b/Documentation/devicetree/bindings/net/fsl-fec.txt @@ -22,6 +22,8 @@ Optional properties: - phy-reset-active-high : If present then the reset sequence using the GPIO specified in the "phy-reset-gpios" property is reversed (H=reset state, L=operation state). +- phy-reset-in-suspend : keeps the phy in reset during suspend mode to + avoid back-drives through the reset line. - phy-reset-post-delay : Post reset delay in milliseconds. If present then a delay of phy-reset-post-delay milliseconds will be observed after the phy-reset-gpios has been toggled. Can be omitted thus no delay is diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index 0052fbb42740..b5ec76c2ca3f 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h @@ -590,6 +590,9 @@ struct fec_enet_private { int wake_irq; u32 quirks; u32 fixups; + int phy_reset_gpio; + bool active_high; + bool phy_reset_in_suspend; struct napi_struct napi; int csum_flags; diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 8bce5a045245..1de1801dfab5 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -3519,10 +3519,11 @@ static void fec_reset_phy_init(void) static int fec_reset_phy(struct platform_device *pdev) { - int err, phy_reset; - bool active_high = false; + int err; int msec = 1, phy_post_delay = 0; struct device_node *np = pdev->dev.of_node; + struct net_device *ndev = platform_get_drvdata(pdev); + struct fec_enet_private *fep = netdev_priv(ndev); if (!np) return 0; @@ -3532,33 +3533,38 @@ static int fec_reset_phy(struct platform_device *pdev) if (!err && msec > 1000) msec = 1; - phy_reset = of_get_named_gpio(np, "phy-reset-gpios", 0); - if (phy_reset == -EPROBE_DEFER) - return phy_reset; - else if (!gpio_is_valid(phy_reset)) + fep->phy_reset_gpio = of_get_named_gpio(np, "phy-reset-gpios", 0); + if (fep->phy_reset_gpio == -EPROBE_DEFER) + return fep->phy_reset_gpio; + else if (!gpio_is_valid(fep->phy_reset_gpio)) { + fep->phy_reset_gpio = -1; return 0; + } err = of_property_read_u32(np, "phy-reset-post-delay", &phy_post_delay); /* valid reset duration should be less than 1s */ if (!err && phy_post_delay > 1000) return -EINVAL; - active_high = of_property_read_bool(np, "phy-reset-active-high"); + fep->active_high = of_property_read_bool(np, "phy-reset-active-high"); - err = devm_gpio_request_one(&pdev->dev, phy_reset, - active_high ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW, + err = devm_gpio_request_one(&pdev->dev, fep->phy_reset_gpio, + fep->active_high ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW, "phy-reset"); if (err) { dev_err(&pdev->dev, "failed to get phy-reset-gpios: %d\n", err); return err; } + fep->phy_reset_in_suspend = of_property_read_bool(np, + "phy-reset-in-suspend"); + if (msec > 20) msleep(msec); else usleep_range(msec * 1000, msec * 1000 + 1000); - gpio_set_value_cansleep(phy_reset, !active_high); + gpio_set_value_cansleep(fep->phy_reset_gpio, !fep->active_high); if (!phy_post_delay) return 0; @@ -3984,6 +3990,8 @@ static int __maybe_unused fec_suspend(struct device *dev) fec_stop(ndev); if (!(fep->wol_flag & FEC_WOL_FLAG_ENABLE)) { fec_irqs_disable(ndev); + if (fep->phy_reset_in_suspend) + gpio_set_value_cansleep(fep->phy_reset_gpio, fep->active_high); pinctrl_pm_select_sleep_state(&fep->pdev->dev); } else { disable_irq(fep->wake_irq); @@ -3996,6 +4004,8 @@ static int __maybe_unused fec_suspend(struct device *dev) if (ret < 0) return ret; } else if (fep->mii_bus_share && !ndev->phydev) { + if (fep->phy_reset_in_suspend) + gpio_set_value_cansleep(fep->phy_reset_gpio, fep->active_high); pinctrl_pm_select_sleep_state(&fep->pdev->dev); } rtnl_unlock(); @@ -4044,6 +4054,8 @@ static int __maybe_unused fec_resume(struct device *dev) writel(val, fep->hwp + FEC_ECNTRL); fep->wol_flag &= ~FEC_WOL_FLAG_SLEEP_ON; } else { + if (fep->phy_reset_in_suspend) + gpio_set_value_cansleep(fep->phy_reset_gpio, !fep->active_high); pinctrl_pm_select_default_state(&fep->pdev->dev); } fec_restart(ndev); @@ -4053,6 +4065,8 @@ static int __maybe_unused fec_resume(struct device *dev) napi_enable(&fep->napi); phy_start(ndev->phydev); } else if (fep->mii_bus_share && !ndev->phydev) { + if (fep->phy_reset_in_suspend) + gpio_set_value_cansleep(fep->phy_reset_gpio, !fep->active_high); pinctrl_pm_select_default_state(&fep->pdev->dev); /* And then recovery mii bus */ ret = fec_restore_mii_bus(ndev);