diff options
author | Richard Leitner <richard.leitner@skidata.com> | 2017-12-11 15:16:58 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-12-13 19:22:53 +0300 |
commit | a96684914adb4adb9f81faf6917e0673b92288d8 (patch) | |
tree | c1140d2c4f2df5c11bfc460bb1500cf1b11149a5 /drivers | |
parent | 3a30ae6ef3cba29c83ca791bde0d06f182d5678d (diff) | |
download | linux-a96684914adb4adb9f81faf6917e0673b92288d8.tar.xz |
phylib: add reset after clk enable support
Some PHYs need the refclk to be a continuous clock. Therefore they don't
allow turning it off and on again during operation. Nonetheless such a
clock switching is performed by some ETH drivers (namely FEC [1]) for
power saving reasons. An example for an affected PHY is the
SMSC/Microchip LAN8720 in "REF_CLK In Mode".
In order to provide a uniform method to overcome this problem this patch
adds a new phy_driver flag (PHY_RST_AFTER_CLK_EN) and corresponding
function phy_reset_after_clk_enable() to the phylib. These should be
used to trigger reset of the PHY after the refclk is switched on again.
[1] commit e8fcfcd5684a ("net: fec: optimize the clock management to save power")
Signed-off-by: Richard Leitner <richard.leitner@skidata.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/phy/phy_device.c | 24 |
1 files changed, 24 insertions, 0 deletions
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 1de5e242b8b4..462c17ed87b8 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1218,6 +1218,30 @@ out: } EXPORT_SYMBOL(phy_loopback); +/** + * phy_reset_after_clk_enable - perform a PHY reset if needed + * @phydev: target phy_device struct + * + * Description: Some PHYs are known to need a reset after their refclk was + * enabled. This function evaluates the flags and perform the reset if it's + * needed. Returns < 0 on error, 0 if the phy wasn't reset and 1 if the phy + * was reset. + */ +int phy_reset_after_clk_enable(struct phy_device *phydev) +{ + if (!phydev || !phydev->drv) + return -ENODEV; + + if (phydev->drv->flags & PHY_RST_AFTER_CLK_EN) { + phy_device_reset(phydev, 1); + phy_device_reset(phydev, 0); + return 1; + } + + return 0; +} +EXPORT_SYMBOL(phy_reset_after_clk_enable); + /* Generic PHY support and helper functions */ /** |