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: Florian Fainelli <f.fainelli@gmail.com> Reviewed-by: Andrew Lunn <andrew@lunn.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
5f3666e839
commit
ba4ee3c053
|
@ -11,6 +11,7 @@
|
|||
#include "bcm-phy-lib.h"
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/brcmphy.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/mdio.h>
|
||||
|
||||
/* Broadcom BCM7xxx internal PHY registers */
|
||||
|
@ -39,6 +40,7 @@
|
|||
|
||||
struct bcm7xxx_phy_priv {
|
||||
u64 *stats;
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
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,
|
|||
static int bcm7xxx_28nm_probe(struct phy_device *phydev)
|
||||
{
|
||||
struct bcm7xxx_phy_priv *priv;
|
||||
int ret = 0;
|
||||
|
||||
priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
|
@ -534,7 +537,30 @@ static int bcm7xxx_28nm_probe(struct phy_device *phydev)
|
|||
if (!priv->stats)
|
||||
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) \
|
||||
|
@ -552,6 +578,7 @@ static int bcm7xxx_28nm_probe(struct phy_device *phydev)
|
|||
.get_strings = bcm_phy_get_strings, \
|
||||
.get_stats = bcm7xxx_28nm_get_phy_stats, \
|
||||
.probe = bcm7xxx_28nm_probe, \
|
||||
.remove = bcm7xxx_28nm_remove, \
|
||||
}
|
||||
|
||||
#define BCM7XXX_28NM_EPHY(_oui, _name) \
|
||||
|
@ -567,6 +594,7 @@ static int bcm7xxx_28nm_probe(struct phy_device *phydev)
|
|||
.get_strings = bcm_phy_get_strings, \
|
||||
.get_stats = bcm7xxx_28nm_get_phy_stats, \
|
||||
.probe = bcm7xxx_28nm_probe, \
|
||||
.remove = bcm7xxx_28nm_remove, \
|
||||
}
|
||||
|
||||
#define BCM7XXX_40NM_EPHY(_oui, _name) \
|
||||
|
|
Loading…
Reference in New Issue