return ret;
}
+#ifdef CONFIG_OF
+static void fec_reset_phy(struct platform_device *pdev)
+{
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct fec_enet_private *fep = netdev_priv(ndev);
+ u32 msec = fep->phy_reset_duration;
+
+ if (fep->phy_reset_gpio < 0)
+ return;
+
+ gpio_set_value_cansleep(fep->phy_reset_gpio,
+ fep->phy_reset_active_high);
+ if (msec > 20)
+ msleep(msec);
+ else
+ usleep_range(msec * 1000, msec * 1000 + 1000);
+
+ gpio_set_value_cansleep(fep->phy_reset_gpio,
+ !fep->phy_reset_active_high);
+
+ if (!fep->phy_post_delay)
+ return;
+
+ if (fep->phy_post_delay > 20)
+ msleep(fep->phy_post_delay);
+ else
+ usleep_range(fep->phy_post_delay * 1000,
+ fep->phy_post_delay * 1000 + 1000);
+
+ return;
+}
+
+#else /* CONFIG_OF */
+static int fec_reset_phy(struct platform_device *pdev)
+{
+ /*
+ * In case of platform probe, the reset has been done
+ * by machine code.
+ */
+ return 0;
+}
+#endif /* CONFIG_OF */
+
static void fec_enet_phy_reset_after_clk_enable(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
struct phy_device *phy_dev = ndev->phydev;
if (phy_dev) {
- phy_reset_after_clk_enable(phy_dev);
+ if (!gpio_is_valid(fep->phy_reset_gpio)) {
+ phy_reset_after_clk_enable(phy_dev);
+ } else {
+ if (phy_dev && phy_dev->drv &&
+ phy_dev->drv->flags & PHY_RST_AFTER_CLK_EN) {
+ fec_reset_phy(fep->pdev);
+ }
+ }
} else if (fep->phy_node) {
/*
* If the PHY still is not bound to the MAC, but there is
* the PHY reset.
*/
phy_dev = of_phy_find_device(fep->phy_node);
- phy_reset_after_clk_enable(phy_dev);
+ if (!gpio_is_valid(fep->phy_reset_gpio)) {
+ phy_reset_after_clk_enable(phy_dev);
+ } else {
+ if (phy_dev && phy_dev->drv &&
+ phy_dev->drv->flags & PHY_RST_AFTER_CLK_EN) {
+ fec_reset_phy(fep->pdev);
+ }
+ }
put_device(&phy_dev->mdio.dev);
}
}
}
#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, 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);
+ int err;
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;
+ if (err || fep->phy_reset_duration > 1000)
+ fep->phy_reset_duration = 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))
return 0;
- err = of_property_read_u32(np, "phy-reset-post-delay", &phy_post_delay);
+ err = of_property_read_u32(np, "phy-reset-post-delay",
+ &fep->phy_post_delay);
/* valid reset duration should be less than 1s */
- if (!err && phy_post_delay > 1000)
+ if (!err && fep->phy_post_delay > 1000)
return -EINVAL;
- active_high = of_property_read_bool(np, "phy-reset-active-high");
+ fep->phy_reset_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,
- "phy-reset");
+ err = devm_gpio_request_one(&pdev->dev, fep->phy_reset_gpio,
+ fep->phy_reset_active_high ?
+ GPIOF_OUT_INIT_LOW :
+ GPIOF_OUT_INIT_HIGH,
+ "phy-reset");
if (err) {
dev_err(&pdev->dev, "failed to get phy-reset-gpios: %d\n", err);
return err;
}
-
- if (msec > 20)
- msleep(msec);
- else
- usleep_range(msec * 1000, msec * 1000 + 1000);
-
- gpio_set_value_cansleep(phy_reset, !active_high);
-
- if (!phy_post_delay)
- return 0;
-
- if (phy_post_delay > 20)
- msleep(phy_post_delay);
- else
- usleep_range(phy_post_delay * 1000,
- phy_post_delay * 1000 + 1000);
+ fep->phy_reset_in_suspend = of_find_property(np,
+ "phy-reset-in-suspend",
+ NULL);
return 0;
}
-#else /* CONFIG_OF */
-static int fec_reset_phy(struct platform_device *pdev)
-{
- /*
- * In case of platform probe, the reset has been done
- * by machine code.
- */
- return 0;
-}
#endif /* CONFIG_OF */
static void
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
- ret = fec_reset_phy(pdev);
+ ret = fec_reset_phy_init(pdev);
if (ret)
goto failed_reset;
irq_cnt = fec_enet_get_irq_cnt(pdev);
+
+ fec_reset_phy(pdev);
+
if (fep->bufdesc_ex)
fec_ptp_init(pdev, irq_cnt);
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->phy_reset_active_high);
pinctrl_pm_select_sleep_state(&fep->pdev->dev);
} else {
fec_enet_stop_mode(fep, true);
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->phy_reset_active_high);
pinctrl_pm_select_sleep_state(&fep->pdev->dev);
}
rtnl_unlock();
fep->wol_flag &= ~FEC_WOL_FLAG_SLEEP_ON;
} else {
pinctrl_pm_select_default_state(&fep->pdev->dev);
+ if (fep->phy_reset_in_suspend)
+ gpio_set_value_cansleep(fep->phy_reset_gpio,
+ !fep->phy_reset_active_high);
}
fec_restart(ndev);
netif_tx_lock_bh(ndev);
phy_start(ndev->phydev);
} else if (fep->mii_bus_share && !ndev->phydev) {
pinctrl_pm_select_default_state(&fep->pdev->dev);
+ if (fep->phy_reset_in_suspend)
+ gpio_set_value_cansleep(fep->phy_reset_gpio,
+ !fep->phy_reset_active_high);
/* And then recovery mii bus */
ret = fec_restore_mii_bus(ndev);
}