Commit ba4ee3c0 authored by Florian Fainelli's avatar Florian Fainelli Committed by David S. Miller

net: phy: bcm7xxx: request and manage GPHY clock

The internal Gigabit PHY on Broadcom STB chips has a digital clock which
drives its MDIO interface among other things, the driver now requests
and manage that clock during .probe() and .remove() accordingly.

Because the PHY driver can be probed with the clocks turned off we need
to apply the dummy BMSR workaround during the driver probe function to
ensure subsequent MDIO read or write towards the PHY will succeed.
Signed-off-by: default avatarFlorian Fainelli <f.fainelli@gmail.com>
Reviewed-by: default avatarAndrew Lunn <andrew@lunn.ch>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 5f3666e8
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "bcm-phy-lib.h" #include "bcm-phy-lib.h"
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/brcmphy.h> #include <linux/brcmphy.h>
#include <linux/clk.h>
#include <linux/mdio.h> #include <linux/mdio.h>
/* Broadcom BCM7xxx internal PHY registers */ /* Broadcom BCM7xxx internal PHY registers */
...@@ -39,6 +40,7 @@ ...@@ -39,6 +40,7 @@
struct bcm7xxx_phy_priv { struct bcm7xxx_phy_priv {
u64 *stats; u64 *stats;
struct clk *clk;
}; };
static int bcm7xxx_28nm_d0_afe_config_init(struct phy_device *phydev) static int bcm7xxx_28nm_d0_afe_config_init(struct phy_device *phydev)
...@@ -521,6 +523,7 @@ static void bcm7xxx_28nm_get_phy_stats(struct phy_device *phydev, ...@@ -521,6 +523,7 @@ static void bcm7xxx_28nm_get_phy_stats(struct phy_device *phydev,
static int bcm7xxx_28nm_probe(struct phy_device *phydev) static int bcm7xxx_28nm_probe(struct phy_device *phydev)
{ {
struct bcm7xxx_phy_priv *priv; struct bcm7xxx_phy_priv *priv;
int ret = 0;
priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
if (!priv) if (!priv)
...@@ -534,7 +537,30 @@ static int bcm7xxx_28nm_probe(struct phy_device *phydev) ...@@ -534,7 +537,30 @@ static int bcm7xxx_28nm_probe(struct phy_device *phydev)
if (!priv->stats) if (!priv->stats)
return -ENOMEM; return -ENOMEM;
return 0; priv->clk = devm_clk_get_optional(&phydev->mdio.dev, NULL);
if (IS_ERR(priv->clk))
return PTR_ERR(priv->clk);
ret = clk_prepare_enable(priv->clk);
if (ret)
return ret;
/* Dummy read to a register to workaround an issue upon reset where the
* internal inverter may not allow the first MDIO transaction to pass
* the MDIO management controller and make us return 0xffff for such
* reads. This is needed to ensure that any subsequent reads to the
* PHY will succeed.
*/
phy_read(phydev, MII_BMSR);
return ret;
}
static void bcm7xxx_28nm_remove(struct phy_device *phydev)
{
struct bcm7xxx_phy_priv *priv = phydev->priv;
clk_disable_unprepare(priv->clk);
} }
#define BCM7XXX_28NM_GPHY(_oui, _name) \ #define BCM7XXX_28NM_GPHY(_oui, _name) \
...@@ -552,6 +578,7 @@ static int bcm7xxx_28nm_probe(struct phy_device *phydev) ...@@ -552,6 +578,7 @@ static int bcm7xxx_28nm_probe(struct phy_device *phydev)
.get_strings = bcm_phy_get_strings, \ .get_strings = bcm_phy_get_strings, \
.get_stats = bcm7xxx_28nm_get_phy_stats, \ .get_stats = bcm7xxx_28nm_get_phy_stats, \
.probe = bcm7xxx_28nm_probe, \ .probe = bcm7xxx_28nm_probe, \
.remove = bcm7xxx_28nm_remove, \
} }
#define BCM7XXX_28NM_EPHY(_oui, _name) \ #define BCM7XXX_28NM_EPHY(_oui, _name) \
...@@ -567,6 +594,7 @@ static int bcm7xxx_28nm_probe(struct phy_device *phydev) ...@@ -567,6 +594,7 @@ static int bcm7xxx_28nm_probe(struct phy_device *phydev)
.get_strings = bcm_phy_get_strings, \ .get_strings = bcm_phy_get_strings, \
.get_stats = bcm7xxx_28nm_get_phy_stats, \ .get_stats = bcm7xxx_28nm_get_phy_stats, \
.probe = bcm7xxx_28nm_probe, \ .probe = bcm7xxx_28nm_probe, \
.remove = bcm7xxx_28nm_remove, \
} }
#define BCM7XXX_40NM_EPHY(_oui, _name) \ #define BCM7XXX_40NM_EPHY(_oui, _name) \
......
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