From: Fugang Duan Date: Sun, 29 Sep 2013 06:56:16 +0000 (+0800) Subject: ENGR00279948 net: fec: add clock control to save power X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=238c59eab19a8aff7233643eb1df07abb7c1a5af;p=karo-tx-linux.git ENGR00279948 net: fec: add clock control to save power - After probe, disable all clocks incluing ipg, ahb, enet_out, ptp clock. - Open ethx interface enable necessary clocks. Close ethx interface disable all clocks. - Correct the MDIO clock source. Signed-off-by: Fugang Duan --- diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 598d9ec8eea6..93840d445613 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -1263,6 +1263,27 @@ static int fec_enet_mdio_reset(struct mii_bus *bus) return 0; } +static inline void fec_enet_clk_enable(struct net_device *ndev, bool enable) +{ + struct fec_enet_private *fep = netdev_priv(ndev); + + if (enable) { + clk_prepare_enable(fep->clk_ahb); + clk_prepare_enable(fep->clk_ipg); + if (fep->clk_enet_out) + clk_prepare_enable(fep->clk_enet_out); + if (fep->clk_ptp) + clk_prepare_enable(fep->clk_ptp); + } else { + clk_disable_unprepare(fep->clk_ahb); + clk_disable_unprepare(fep->clk_ipg); + if (fep->clk_enet_out) + clk_disable_unprepare(fep->clk_enet_out); + if (fep->clk_ptp) + clk_disable_unprepare(fep->clk_ptp); + } +} + static int fec_enet_mii_probe(struct net_device *ndev) { struct fec_enet_private *fep = netdev_priv(ndev); @@ -1372,7 +1393,7 @@ static int fec_enet_mii_init(struct platform_device *pdev) * Reference Manual has an error on this, and gets fixed on i.MX6Q * document. */ - fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk_ahb), 5000000); + fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk_ipg), 5000000); if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) fep->phy_speed--; fep->phy_speed <<= 1; @@ -1779,6 +1800,8 @@ fec_enet_open(struct net_device *ndev) pm_runtime_get_sync(ndev->dev.parent); + fec_enet_clk_enable(ndev, true); + napi_enable(&fep->napi); /* I should reset the ring buffers here, but I don't yet know @@ -1822,6 +1845,8 @@ fec_enet_close(struct net_device *ndev) phy_disconnect(fep->phy_dev); } + fec_enet_clk_enable(ndev, false); + pm_runtime_put_sync_suspend(ndev->dev.parent); fec_enet_free_buffers(ndev); @@ -2178,17 +2203,14 @@ fec_probe(struct platform_device *pdev) fep->clk_ptp = devm_clk_get(&pdev->dev, "ptp"); fep->bufdesc_ex = pdev->id_entry->driver_data & FEC_QUIRK_HAS_BUFDESC_EX; - if (IS_ERR(fep->clk_ptp)) { + if (IS_ERR(fep->clk_ptp) || !fep->bufdesc_ex) { fep->clk_ptp = NULL; fep->bufdesc_ex = 0; } pm_runtime_enable(&pdev->dev); - clk_prepare_enable(fep->clk_ahb); - clk_prepare_enable(fep->clk_ipg); - clk_prepare_enable(fep->clk_enet_out); - clk_prepare_enable(fep->clk_ptp); + fec_enet_clk_enable(ndev, true); fep->reg_phy = devm_regulator_get(&pdev->dev, "phy"); if (!IS_ERR(fep->reg_phy)) { @@ -2233,6 +2255,7 @@ fec_probe(struct platform_device *pdev) /* Carrier starts down, phylib will bring it up */ netif_carrier_off(ndev); + fec_enet_clk_enable(ndev, false); ret = register_netdev(ndev); if (ret) @@ -2257,10 +2280,7 @@ failed_init: if (fep->reg_phy) regulator_disable(fep->reg_phy); failed_regulator: - clk_disable_unprepare(fep->clk_ahb); - clk_disable_unprepare(fep->clk_ipg); - clk_disable_unprepare(fep->clk_enet_out); - clk_disable_unprepare(fep->clk_ptp); + fec_enet_clk_enable(ndev, false); failed_clk: failed_ioremap: free_netdev(ndev); @@ -2290,13 +2310,10 @@ fec_drv_remove(struct platform_device *pdev) if (fep->reg_phy) regulator_disable(fep->reg_phy); if (fep->bufdesc_ex) { - clk_disable_unprepare(fep->clk_ptp); if (fep->ptp_clock) ptp_clock_unregister(fep->ptp_clock); } - clk_disable_unprepare(fep->clk_enet_out); - clk_disable_unprepare(fep->clk_ahb); - clk_disable_unprepare(fep->clk_ipg); + fec_enet_clk_enable(ndev, false); free_netdev(ndev); return 0; @@ -2313,10 +2330,8 @@ fec_suspend(struct device *dev) fec_stop(ndev); netif_device_detach(ndev); } - clk_disable_unprepare(fep->clk_enet_out); - clk_disable_unprepare(fep->clk_ahb); - clk_disable_unprepare(fep->clk_ipg); + fec_enet_clk_enable(ndev, false); if (fep->reg_phy) regulator_disable(fep->reg_phy); @@ -2336,9 +2351,7 @@ fec_resume(struct device *dev) return ret; } - clk_prepare_enable(fep->clk_enet_out); - clk_prepare_enable(fep->clk_ahb); - clk_prepare_enable(fep->clk_ipg); + fec_enet_clk_enable(ndev, true); if (netif_running(ndev)) { fec_restart(ndev, fep->full_duplex); netif_device_attach(ndev);