Enable PHY reset line when the fec is probed
authorJosep Orga <jorga@somdevices.com>
Mon, 6 May 2019 08:45:17 +0000 (10:45 +0200)
committerJosep Orga <jorga@somdevices.com>
Mon, 6 May 2019 08:45:17 +0000 (10:45 +0200)
Based on: https://github.com/digi-embedded/linux/commit/f0ddbc0153b269bfd21b84dbd4ad16acdfd21f29#diff-28c0935b4b5bf1738a0ee788d25a18ff

Signed-off-by: Josep Orga <jorga@somdevices.com>
drivers/net/ethernet/freescale/fec.h
drivers/net/ethernet/freescale/fec_main.c

index 71d6222..df0c1d6 100644 (file)
@@ -582,6 +582,9 @@ struct fec_enet_private {
        int     wake_irq;
        u32     quirks;
        u32     fixups;
+       int     phy_reset_gpio;
+       u32     phy_reset_duration;
+       bool    active_high;
 
        struct  napi_struct napi;
        int     csum_flags;
index 6ab85fd..3482309 100644 (file)
@@ -3458,47 +3458,74 @@ static int fec_enet_init(struct net_device *ndev)
 }
 
 #ifdef CONFIG_OF
-static int fec_reset_phy(struct platform_device *pdev)
+static int fec_reset_phy_init(struct platform_device *pdev)
 {
-       int err, phy_reset;
-       bool active_high = false;
-       int msec = 1;
+       int err;
        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;
 
-       err = of_property_read_u32(np, "phy-reset-duration", &msec);
+       err = of_property_read_u32(np, "phy-reset-duration", &fep->phy_reset_duration);
        /* A sane reset duration should not be longer than 1s */
-       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))
+       if (!err && fep->phy_reset_duration > 1000)
+               fep->phy_reset_duration = 1;
+
+       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;
+       }
 
-       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;
        }
-
-       if (msec > 20)
-               msleep(msec);
+       /* Enable PHY and wait for stabilization */
+       gpio_set_value_cansleep(fep->phy_reset_gpio, !fep->active_high);
+       if (fep->phy_reset_duration < 20)
+               msleep(20);
        else
-               usleep_range(msec * 1000, msec * 1000 + 1000);
+               msleep(fep->phy_reset_duration);
+       return 0;
+}
 
-       gpio_set_value_cansleep(phy_reset, !active_high);
+static int fec_reset_phy(struct platform_device *pdev)
+{
+       struct net_device *ndev = platform_get_drvdata(pdev);
+       struct fec_enet_private *fep = netdev_priv(ndev);
 
+       if (fep->phy_reset_gpio < 0)
+               return 0;
+
+       gpio_set_value_cansleep(fep->phy_reset_gpio, fep->active_high);
+       if (fep->phy_reset_duration > 20)
+               msleep(fep->phy_reset_duration);
+       else
+               usleep_range(fep->phy_reset_duration * 1000, fep->phy_reset_duration * 1000 + 1000);
+       gpio_set_value_cansleep(fep->phy_reset_gpio, !fep->active_high);
        return 0;
 }
+
 #else /* CONFIG_OF */
+static int fec_reset_phy_init(struct platform_device *pdev)
+{
+       /*
+        * In case of platform probe, the reset has been done
+        * by machine code.
+        */
+       return 0;
+}
+
 static int fec_reset_phy(struct platform_device *pdev)
 {
        /*
@@ -3689,6 +3716,9 @@ fec_probe(struct platform_device *pdev)
        }
        fep->itr_clk_rate = clk_get_rate(fep->clk_ahb);
 
+       /* Enable reset PHY line */
+       fec_reset_phy_init(pdev);
+
        /* enet_out is optional, depends on board */
        fep->clk_enet_out = devm_clk_get(&pdev->dev, "enet_out");
        if (IS_ERR(fep->clk_enet_out))