forked from mirrors/linux
		
	net: fec: optimize the clock management to save power
Add below clock management to save fec 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. The patch also encapsulates the all enet clocks enable/disable to .fec_enet_clk_enable(), which can reduce the repetitional code in driver. Signed-off-by: Fugang Duan <B38611@freescale.com> Acked-by: Frank Li <Frank.li@freescale.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									fddb88723c
								
							
						
					
					
						commit
						e8fcfcd568
					
				
					 1 changed files with 56 additions and 64 deletions
				
			
		|  | @ -1255,6 +1255,49 @@ static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum, | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static int fec_enet_clk_enable(struct net_device *ndev, bool enable) | ||||||
|  | { | ||||||
|  | 	struct fec_enet_private *fep = netdev_priv(ndev); | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	if (enable) { | ||||||
|  | 		ret = clk_prepare_enable(fep->clk_ahb); | ||||||
|  | 		if (ret) | ||||||
|  | 			return ret; | ||||||
|  | 		ret = clk_prepare_enable(fep->clk_ipg); | ||||||
|  | 		if (ret) | ||||||
|  | 			goto failed_clk_ipg; | ||||||
|  | 		if (fep->clk_enet_out) { | ||||||
|  | 			ret = clk_prepare_enable(fep->clk_enet_out); | ||||||
|  | 			if (ret) | ||||||
|  | 				goto failed_clk_enet_out; | ||||||
|  | 		} | ||||||
|  | 		if (fep->clk_ptp) { | ||||||
|  | 			ret = clk_prepare_enable(fep->clk_ptp); | ||||||
|  | 			if (ret) | ||||||
|  | 				goto failed_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); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | failed_clk_ptp: | ||||||
|  | 	if (fep->clk_enet_out) | ||||||
|  | 		clk_disable_unprepare(fep->clk_enet_out); | ||||||
|  | failed_clk_enet_out: | ||||||
|  | 		clk_disable_unprepare(fep->clk_ipg); | ||||||
|  | failed_clk_ipg: | ||||||
|  | 		clk_disable_unprepare(fep->clk_ahb); | ||||||
|  | 
 | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static int fec_enet_mii_probe(struct net_device *ndev) | static int fec_enet_mii_probe(struct net_device *ndev) | ||||||
| { | { | ||||||
| 	struct fec_enet_private *fep = netdev_priv(ndev); | 	struct fec_enet_private *fep = netdev_priv(ndev); | ||||||
|  | @ -1773,6 +1816,10 @@ fec_enet_open(struct net_device *ndev) | ||||||
| 	struct fec_enet_private *fep = netdev_priv(ndev); | 	struct fec_enet_private *fep = netdev_priv(ndev); | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
|  | 	ret = fec_enet_clk_enable(ndev, true); | ||||||
|  | 	if (ret) | ||||||
|  | 		return ret; | ||||||
|  | 
 | ||||||
| 	/* I should reset the ring buffers here, but I don't yet know
 | 	/* I should reset the ring buffers here, but I don't yet know
 | ||||||
| 	 * a simple way to do that. | 	 * a simple way to do that. | ||||||
| 	 */ | 	 */ | ||||||
|  | @ -1811,6 +1858,7 @@ fec_enet_close(struct net_device *ndev) | ||||||
| 		phy_disconnect(fep->phy_dev); | 		phy_disconnect(fep->phy_dev); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	fec_enet_clk_enable(ndev, false); | ||||||
| 	fec_enet_free_buffers(ndev); | 	fec_enet_free_buffers(ndev); | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  | @ -2164,26 +2212,10 @@ fec_probe(struct platform_device *pdev) | ||||||
| 		fep->bufdesc_ex = 0; | 		fep->bufdesc_ex = 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	ret = clk_prepare_enable(fep->clk_ahb); | 	ret = fec_enet_clk_enable(ndev, true); | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		goto failed_clk; | 		goto failed_clk; | ||||||
| 
 | 
 | ||||||
| 	ret = clk_prepare_enable(fep->clk_ipg); |  | ||||||
| 	if (ret) |  | ||||||
| 		goto failed_clk_ipg; |  | ||||||
| 
 |  | ||||||
| 	if (fep->clk_enet_out) { |  | ||||||
| 		ret = clk_prepare_enable(fep->clk_enet_out); |  | ||||||
| 		if (ret) |  | ||||||
| 			goto failed_clk_enet_out; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (fep->clk_ptp) { |  | ||||||
| 		ret = clk_prepare_enable(fep->clk_ptp); |  | ||||||
| 		if (ret) |  | ||||||
| 			goto failed_clk_ptp; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	fep->reg_phy = devm_regulator_get(&pdev->dev, "phy"); | 	fep->reg_phy = devm_regulator_get(&pdev->dev, "phy"); | ||||||
| 	if (!IS_ERR(fep->reg_phy)) { | 	if (!IS_ERR(fep->reg_phy)) { | ||||||
| 		ret = regulator_enable(fep->reg_phy); | 		ret = regulator_enable(fep->reg_phy); | ||||||
|  | @ -2225,6 +2257,7 @@ fec_probe(struct platform_device *pdev) | ||||||
| 
 | 
 | ||||||
| 	/* Carrier starts down, phylib will bring it up */ | 	/* Carrier starts down, phylib will bring it up */ | ||||||
| 	netif_carrier_off(ndev); | 	netif_carrier_off(ndev); | ||||||
|  | 	fec_enet_clk_enable(ndev, false); | ||||||
| 
 | 
 | ||||||
| 	ret = register_netdev(ndev); | 	ret = register_netdev(ndev); | ||||||
| 	if (ret) | 	if (ret) | ||||||
|  | @ -2244,15 +2277,7 @@ fec_probe(struct platform_device *pdev) | ||||||
| 	if (fep->reg_phy) | 	if (fep->reg_phy) | ||||||
| 		regulator_disable(fep->reg_phy); | 		regulator_disable(fep->reg_phy); | ||||||
| failed_regulator: | failed_regulator: | ||||||
| 	if (fep->clk_ptp) | 	fec_enet_clk_enable(ndev, false); | ||||||
| 		clk_disable_unprepare(fep->clk_ptp); |  | ||||||
| failed_clk_ptp: |  | ||||||
| 	if (fep->clk_enet_out) |  | ||||||
| 		clk_disable_unprepare(fep->clk_enet_out); |  | ||||||
| failed_clk_enet_out: |  | ||||||
| 	clk_disable_unprepare(fep->clk_ipg); |  | ||||||
| failed_clk_ipg: |  | ||||||
| 	clk_disable_unprepare(fep->clk_ahb); |  | ||||||
| failed_clk: | failed_clk: | ||||||
| failed_ioremap: | failed_ioremap: | ||||||
| 	free_netdev(ndev); | 	free_netdev(ndev); | ||||||
|  | @ -2272,14 +2297,9 @@ fec_drv_remove(struct platform_device *pdev) | ||||||
| 	del_timer_sync(&fep->time_keep); | 	del_timer_sync(&fep->time_keep); | ||||||
| 	if (fep->reg_phy) | 	if (fep->reg_phy) | ||||||
| 		regulator_disable(fep->reg_phy); | 		regulator_disable(fep->reg_phy); | ||||||
| 	if (fep->clk_ptp) |  | ||||||
| 		clk_disable_unprepare(fep->clk_ptp); |  | ||||||
| 	if (fep->ptp_clock) | 	if (fep->ptp_clock) | ||||||
| 		ptp_clock_unregister(fep->ptp_clock); | 		ptp_clock_unregister(fep->ptp_clock); | ||||||
| 	if (fep->clk_enet_out) | 	fec_enet_clk_enable(ndev, false); | ||||||
| 		clk_disable_unprepare(fep->clk_enet_out); |  | ||||||
| 	clk_disable_unprepare(fep->clk_ipg); |  | ||||||
| 	clk_disable_unprepare(fep->clk_ahb); |  | ||||||
| 	free_netdev(ndev); | 	free_netdev(ndev); | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  | @ -2296,12 +2316,7 @@ fec_suspend(struct device *dev) | ||||||
| 		fec_stop(ndev); | 		fec_stop(ndev); | ||||||
| 		netif_device_detach(ndev); | 		netif_device_detach(ndev); | ||||||
| 	} | 	} | ||||||
| 	if (fep->clk_ptp) | 	fec_enet_clk_enable(ndev, false); | ||||||
| 		clk_disable_unprepare(fep->clk_ptp); |  | ||||||
| 	if (fep->clk_enet_out) |  | ||||||
| 		clk_disable_unprepare(fep->clk_enet_out); |  | ||||||
| 	clk_disable_unprepare(fep->clk_ipg); |  | ||||||
| 	clk_disable_unprepare(fep->clk_ahb); |  | ||||||
| 
 | 
 | ||||||
| 	if (fep->reg_phy) | 	if (fep->reg_phy) | ||||||
| 		regulator_disable(fep->reg_phy); | 		regulator_disable(fep->reg_phy); | ||||||
|  | @ -2322,25 +2337,9 @@ fec_resume(struct device *dev) | ||||||
| 			return ret; | 			return ret; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	ret = clk_prepare_enable(fep->clk_ahb); | 	ret = fec_enet_clk_enable(ndev, true); | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		goto failed_clk_ahb; | 		goto failed_clk; | ||||||
| 
 |  | ||||||
| 	ret = clk_prepare_enable(fep->clk_ipg); |  | ||||||
| 	if (ret) |  | ||||||
| 		goto failed_clk_ipg; |  | ||||||
| 
 |  | ||||||
| 	if (fep->clk_enet_out) { |  | ||||||
| 		ret = clk_prepare_enable(fep->clk_enet_out); |  | ||||||
| 		if (ret) |  | ||||||
| 			goto failed_clk_enet_out; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (fep->clk_ptp) { |  | ||||||
| 		ret = clk_prepare_enable(fep->clk_ptp); |  | ||||||
| 		if (ret) |  | ||||||
| 			goto failed_clk_ptp; |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	if (netif_running(ndev)) { | 	if (netif_running(ndev)) { | ||||||
| 		fec_restart(ndev, fep->full_duplex); | 		fec_restart(ndev, fep->full_duplex); | ||||||
|  | @ -2349,14 +2348,7 @@ fec_resume(struct device *dev) | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| 
 | 
 | ||||||
| failed_clk_ptp: | failed_clk: | ||||||
| 	if (fep->clk_enet_out) |  | ||||||
| 		clk_disable_unprepare(fep->clk_enet_out); |  | ||||||
| failed_clk_enet_out: |  | ||||||
| 	clk_disable_unprepare(fep->clk_ipg); |  | ||||||
| failed_clk_ipg: |  | ||||||
| 	clk_disable_unprepare(fep->clk_ahb); |  | ||||||
| failed_clk_ahb: |  | ||||||
| 	if (fep->reg_phy) | 	if (fep->reg_phy) | ||||||
| 		regulator_disable(fep->reg_phy); | 		regulator_disable(fep->reg_phy); | ||||||
| 	return ret; | 	return ret; | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Nimrod Andy
						Nimrod Andy