Commit bedd8d78 authored by Marco Felsch's avatar Marco Felsch Committed by David S. Miller

net: phy: smsc: LAN8710/20: add phy refclk in support

Add support to specify the clock provider for the PHY refclk and don't
rely on 'magic' host clock setup. [1] tried to address this by
introducing a flag and fixing the corresponding host. But this commit
breaks the IRQ support since the irq setup during .config_intr() is
thrown away because the reset comes from the side without respecting the
current PHY state within the PHY library state machine. Furthermore the
commit fixed the problem only for FEC based hosts other hosts acting
like the FEC are not covered.

This commit goes the other way around to address the bug fixed by [1].
Instead of resetting the device from the side every time the refclk gets
(re-)enabled it requests and enables the clock till the device gets
removed. Now the PHY library is the only place where the PHY gets reset
to respect the PHY library state machine.

[1] commit 7f64e5b1 ("net: phy: smsc: LAN8710/20: add
    PHY_RST_AFTER_CLK_EN flag")
Signed-off-by: default avatarMarco Felsch <m.felsch@pengutronix.de>
Reviewed-by: default avatarFlorian Fainelli <f.fainelli@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 84475a9e
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
* *
*/ */
#include <linux/clk.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mii.h> #include <linux/mii.h>
...@@ -44,6 +45,7 @@ static struct smsc_hw_stat smsc_hw_stats[] = { ...@@ -44,6 +45,7 @@ static struct smsc_hw_stat smsc_hw_stats[] = {
struct smsc_phy_priv { struct smsc_phy_priv {
bool energy_enable; bool energy_enable;
struct clk *refclk;
}; };
static int smsc_phy_config_intr(struct phy_device *phydev) static int smsc_phy_config_intr(struct phy_device *phydev)
...@@ -253,11 +255,20 @@ static void smsc_get_stats(struct phy_device *phydev, ...@@ -253,11 +255,20 @@ static void smsc_get_stats(struct phy_device *phydev,
data[i] = smsc_get_stat(phydev, i); data[i] = smsc_get_stat(phydev, i);
} }
static void smsc_phy_remove(struct phy_device *phydev)
{
struct smsc_phy_priv *priv = phydev->priv;
clk_disable_unprepare(priv->refclk);
clk_put(priv->refclk);
}
static int smsc_phy_probe(struct phy_device *phydev) static int smsc_phy_probe(struct phy_device *phydev)
{ {
struct device *dev = &phydev->mdio.dev; struct device *dev = &phydev->mdio.dev;
struct device_node *of_node = dev->of_node; struct device_node *of_node = dev->of_node;
struct smsc_phy_priv *priv; struct smsc_phy_priv *priv;
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv) if (!priv)
...@@ -270,6 +281,19 @@ static int smsc_phy_probe(struct phy_device *phydev) ...@@ -270,6 +281,19 @@ static int smsc_phy_probe(struct phy_device *phydev)
phydev->priv = priv; phydev->priv = priv;
/* Make clk optional to keep DTB backward compatibility. */
priv->refclk = clk_get_optional(dev, NULL);
if (IS_ERR(priv->refclk))
dev_err_probe(dev, PTR_ERR(priv->refclk), "Failed to request clock\n");
ret = clk_prepare_enable(priv->refclk);
if (ret)
return ret;
ret = clk_set_rate(priv->refclk, 50 * 1000 * 1000);
if (ret)
return ret;
return 0; return 0;
} }
...@@ -376,6 +400,7 @@ static struct phy_driver smsc_phy_driver[] = { ...@@ -376,6 +400,7 @@ static struct phy_driver smsc_phy_driver[] = {
.flags = PHY_RST_AFTER_CLK_EN, .flags = PHY_RST_AFTER_CLK_EN,
.probe = smsc_phy_probe, .probe = smsc_phy_probe,
.remove = smsc_phy_remove,
/* basic functions */ /* basic functions */
.read_status = lan87xx_read_status, .read_status = lan87xx_read_status,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment