net: ethernet: fec_main: Add "phy-reset-in-suspend" device tree option. When this...
authorJosep Orga <jorga@somdevices.com>
Sat, 18 Apr 2020 11:33:39 +0000 (13:33 +0200)
committerJosep Orga <jorga@somdevices.com>
Sat, 18 Apr 2020 11:33:39 +0000 (13:33 +0200)
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 <jorga@somdevices.com>
Documentation/devicetree/bindings/net/fsl-fec.txt
drivers/net/ethernet/freescale/fec.h
drivers/net/ethernet/freescale/fec_main.c

index 87f570d..051a223 100644 (file)
@@ -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
index 0052fbb..b5ec76c 100644 (file)
@@ -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;
index 8bce5a0..1de1801 100644 (file)
@@ -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);