diff options
author | Fugang Duan <B38611@freescale.com> | 2013-09-29 02:56:16 -0400 |
---|---|---|
committer | Nitin Garg <nitin.garg@freescale.com> | 2014-04-16 09:05:43 -0400 |
commit | 139b7a73aead3044b1542ef9fc103038f7c868ea (patch) | |
tree | 248ba9be746f28e2521ccc17ddff8b863348ef71 | |
parent | dfa506835ddae328e40f6bf50765037f457b4876 (diff) |
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 <B38611@freescale.com>
-rw-r--r-- | drivers/net/ethernet/freescale/fec_main.c | 53 |
1 files changed, 33 insertions, 20 deletions
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 4c9bdb444907..5b3a8f615ed9 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) | |||
1263 | return 0; | 1263 | return 0; |
1264 | } | 1264 | } |
1265 | 1265 | ||
1266 | static inline void fec_enet_clk_enable(struct net_device *ndev, bool enable) | ||
1267 | { | ||
1268 | struct fec_enet_private *fep = netdev_priv(ndev); | ||
1269 | |||
1270 | if (enable) { | ||
1271 | clk_prepare_enable(fep->clk_ahb); | ||
1272 | clk_prepare_enable(fep->clk_ipg); | ||
1273 | if (fep->clk_enet_out) | ||
1274 | clk_prepare_enable(fep->clk_enet_out); | ||
1275 | if (fep->clk_ptp) | ||
1276 | clk_prepare_enable(fep->clk_ptp); | ||
1277 | } else { | ||
1278 | clk_disable_unprepare(fep->clk_ahb); | ||
1279 | clk_disable_unprepare(fep->clk_ipg); | ||
1280 | if (fep->clk_enet_out) | ||
1281 | clk_disable_unprepare(fep->clk_enet_out); | ||
1282 | if (fep->clk_ptp) | ||
1283 | clk_disable_unprepare(fep->clk_ptp); | ||
1284 | } | ||
1285 | } | ||
1286 | |||
1266 | static int fec_enet_mii_probe(struct net_device *ndev) | 1287 | static int fec_enet_mii_probe(struct net_device *ndev) |
1267 | { | 1288 | { |
1268 | struct fec_enet_private *fep = netdev_priv(ndev); | 1289 | struct fec_enet_private *fep = netdev_priv(ndev); |
@@ -1372,7 +1393,7 @@ static int fec_enet_mii_init(struct platform_device *pdev) | |||
1372 | * Reference Manual has an error on this, and gets fixed on i.MX6Q | 1393 | * Reference Manual has an error on this, and gets fixed on i.MX6Q |
1373 | * document. | 1394 | * document. |
1374 | */ | 1395 | */ |
1375 | fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk_ahb), 5000000); | 1396 | fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk_ipg), 5000000); |
1376 | if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) | 1397 | if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) |
1377 | fep->phy_speed--; | 1398 | fep->phy_speed--; |
1378 | fep->phy_speed <<= 1; | 1399 | fep->phy_speed <<= 1; |
@@ -1779,6 +1800,8 @@ fec_enet_open(struct net_device *ndev) | |||
1779 | 1800 | ||
1780 | pm_runtime_get_sync(ndev->dev.parent); | 1801 | pm_runtime_get_sync(ndev->dev.parent); |
1781 | 1802 | ||
1803 | fec_enet_clk_enable(ndev, true); | ||
1804 | |||
1782 | napi_enable(&fep->napi); | 1805 | napi_enable(&fep->napi); |
1783 | 1806 | ||
1784 | /* I should reset the ring buffers here, but I don't yet know | 1807 | /* I should reset the ring buffers here, but I don't yet know |
@@ -1822,6 +1845,8 @@ fec_enet_close(struct net_device *ndev) | |||
1822 | phy_disconnect(fep->phy_dev); | 1845 | phy_disconnect(fep->phy_dev); |
1823 | } | 1846 | } |
1824 | 1847 | ||
1848 | fec_enet_clk_enable(ndev, false); | ||
1849 | |||
1825 | pm_runtime_put_sync_suspend(ndev->dev.parent); | 1850 | pm_runtime_put_sync_suspend(ndev->dev.parent); |
1826 | 1851 | ||
1827 | fec_enet_free_buffers(ndev); | 1852 | fec_enet_free_buffers(ndev); |
@@ -2178,17 +2203,14 @@ fec_probe(struct platform_device *pdev) | |||
2178 | fep->clk_ptp = devm_clk_get(&pdev->dev, "ptp"); | 2203 | fep->clk_ptp = devm_clk_get(&pdev->dev, "ptp"); |
2179 | fep->bufdesc_ex = | 2204 | fep->bufdesc_ex = |
2180 | pdev->id_entry->driver_data & FEC_QUIRK_HAS_BUFDESC_EX; | 2205 | pdev->id_entry->driver_data & FEC_QUIRK_HAS_BUFDESC_EX; |
2181 | if (IS_ERR(fep->clk_ptp)) { | 2206 | if (IS_ERR(fep->clk_ptp) || !fep->bufdesc_ex) { |
2182 | fep->clk_ptp = NULL; | 2207 | fep->clk_ptp = NULL; |
2183 | fep->bufdesc_ex = 0; | 2208 | fep->bufdesc_ex = 0; |
2184 | } | 2209 | } |
2185 | 2210 | ||
2186 | pm_runtime_enable(&pdev->dev); | 2211 | pm_runtime_enable(&pdev->dev); |
2187 | 2212 | ||
2188 | clk_prepare_enable(fep->clk_ahb); | 2213 | fec_enet_clk_enable(ndev, true); |
2189 | clk_prepare_enable(fep->clk_ipg); | ||
2190 | clk_prepare_enable(fep->clk_enet_out); | ||
2191 | clk_prepare_enable(fep->clk_ptp); | ||
2192 | 2214 | ||
2193 | fep->reg_phy = devm_regulator_get(&pdev->dev, "phy"); | 2215 | fep->reg_phy = devm_regulator_get(&pdev->dev, "phy"); |
2194 | if (!IS_ERR(fep->reg_phy)) { | 2216 | if (!IS_ERR(fep->reg_phy)) { |
@@ -2233,6 +2255,7 @@ fec_probe(struct platform_device *pdev) | |||
2233 | 2255 | ||
2234 | /* Carrier starts down, phylib will bring it up */ | 2256 | /* Carrier starts down, phylib will bring it up */ |
2235 | netif_carrier_off(ndev); | 2257 | netif_carrier_off(ndev); |
2258 | fec_enet_clk_enable(ndev, false); | ||
2236 | 2259 | ||
2237 | ret = register_netdev(ndev); | 2260 | ret = register_netdev(ndev); |
2238 | if (ret) | 2261 | if (ret) |
@@ -2257,10 +2280,7 @@ failed_init: | |||
2257 | if (fep->reg_phy) | 2280 | if (fep->reg_phy) |
2258 | regulator_disable(fep->reg_phy); | 2281 | regulator_disable(fep->reg_phy); |
2259 | failed_regulator: | 2282 | failed_regulator: |
2260 | clk_disable_unprepare(fep->clk_ahb); | 2283 | fec_enet_clk_enable(ndev, false); |
2261 | clk_disable_unprepare(fep->clk_ipg); | ||
2262 | clk_disable_unprepare(fep->clk_enet_out); | ||
2263 | clk_disable_unprepare(fep->clk_ptp); | ||
2264 | failed_clk: | 2284 | failed_clk: |
2265 | failed_ioremap: | 2285 | failed_ioremap: |
2266 | free_netdev(ndev); | 2286 | free_netdev(ndev); |
@@ -2290,13 +2310,10 @@ fec_drv_remove(struct platform_device *pdev) | |||
2290 | if (fep->reg_phy) | 2310 | if (fep->reg_phy) |
2291 | regulator_disable(fep->reg_phy); | 2311 | regulator_disable(fep->reg_phy); |
2292 | if (fep->bufdesc_ex) { | 2312 | if (fep->bufdesc_ex) { |
2293 | clk_disable_unprepare(fep->clk_ptp); | ||
2294 | if (fep->ptp_clock) | 2313 | if (fep->ptp_clock) |
2295 | ptp_clock_unregister(fep->ptp_clock); | 2314 | ptp_clock_unregister(fep->ptp_clock); |
2296 | } | 2315 | } |
2297 | clk_disable_unprepare(fep->clk_enet_out); | 2316 | fec_enet_clk_enable(ndev, false); |
2298 | clk_disable_unprepare(fep->clk_ahb); | ||
2299 | clk_disable_unprepare(fep->clk_ipg); | ||
2300 | free_netdev(ndev); | 2317 | free_netdev(ndev); |
2301 | 2318 | ||
2302 | return 0; | 2319 | return 0; |
@@ -2313,10 +2330,8 @@ fec_suspend(struct device *dev) | |||
2313 | fec_stop(ndev); | 2330 | fec_stop(ndev); |
2314 | netif_device_detach(ndev); | 2331 | netif_device_detach(ndev); |
2315 | } | 2332 | } |
2316 | clk_disable_unprepare(fep->clk_enet_out); | ||
2317 | clk_disable_unprepare(fep->clk_ahb); | ||
2318 | clk_disable_unprepare(fep->clk_ipg); | ||
2319 | 2333 | ||
2334 | fec_enet_clk_enable(ndev, false); | ||
2320 | if (fep->reg_phy) | 2335 | if (fep->reg_phy) |
2321 | regulator_disable(fep->reg_phy); | 2336 | regulator_disable(fep->reg_phy); |
2322 | 2337 | ||
@@ -2336,9 +2351,7 @@ fec_resume(struct device *dev) | |||
2336 | return ret; | 2351 | return ret; |
2337 | } | 2352 | } |
2338 | 2353 | ||
2339 | clk_prepare_enable(fep->clk_enet_out); | 2354 | fec_enet_clk_enable(ndev, true); |
2340 | clk_prepare_enable(fep->clk_ahb); | ||
2341 | clk_prepare_enable(fep->clk_ipg); | ||
2342 | if (netif_running(ndev)) { | 2355 | if (netif_running(ndev)) { |
2343 | fec_restart(ndev, fep->full_duplex); | 2356 | fec_restart(ndev, fep->full_duplex); |
2344 | netif_device_attach(ndev); | 2357 | netif_device_attach(ndev); |