Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Florian Fainelli and committed by
David S. Miller
ba4ee3c0 5f3666e8

+29 -1
+29 -1
drivers/net/phy/bcm7xxx.c
··· 11 11 #include "bcm-phy-lib.h" 12 12 #include <linux/bitops.h> 13 13 #include <linux/brcmphy.h> 14 + #include <linux/clk.h> 14 15 #include <linux/mdio.h> 15 16 16 17 /* Broadcom BCM7xxx internal PHY registers */ ··· 40 39 41 40 struct bcm7xxx_phy_priv { 42 41 u64 *stats; 42 + struct clk *clk; 43 43 }; 44 44 45 45 static int bcm7xxx_28nm_d0_afe_config_init(struct phy_device *phydev) ··· 523 521 static int bcm7xxx_28nm_probe(struct phy_device *phydev) 524 522 { 525 523 struct bcm7xxx_phy_priv *priv; 524 + int ret = 0; 526 525 527 526 priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); 528 527 if (!priv) ··· 537 534 if (!priv->stats) 538 535 return -ENOMEM; 539 536 540 - return 0; 537 + priv->clk = devm_clk_get_optional(&phydev->mdio.dev, NULL); 538 + if (IS_ERR(priv->clk)) 539 + return PTR_ERR(priv->clk); 540 + 541 + ret = clk_prepare_enable(priv->clk); 542 + if (ret) 543 + return ret; 544 + 545 + /* Dummy read to a register to workaround an issue upon reset where the 546 + * internal inverter may not allow the first MDIO transaction to pass 547 + * the MDIO management controller and make us return 0xffff for such 548 + * reads. This is needed to ensure that any subsequent reads to the 549 + * PHY will succeed. 550 + */ 551 + phy_read(phydev, MII_BMSR); 552 + 553 + return ret; 554 + } 555 + 556 + static void bcm7xxx_28nm_remove(struct phy_device *phydev) 557 + { 558 + struct bcm7xxx_phy_priv *priv = phydev->priv; 559 + 560 + clk_disable_unprepare(priv->clk); 541 561 } 542 562 543 563 #define BCM7XXX_28NM_GPHY(_oui, _name) \ ··· 578 552 .get_strings = bcm_phy_get_strings, \ 579 553 .get_stats = bcm7xxx_28nm_get_phy_stats, \ 580 554 .probe = bcm7xxx_28nm_probe, \ 555 + .remove = bcm7xxx_28nm_remove, \ 581 556 } 582 557 583 558 #define BCM7XXX_28NM_EPHY(_oui, _name) \ ··· 594 567 .get_strings = bcm_phy_get_strings, \ 595 568 .get_stats = bcm7xxx_28nm_get_phy_stats, \ 596 569 .probe = bcm7xxx_28nm_probe, \ 570 + .remove = bcm7xxx_28nm_remove, \ 597 571 } 598 572 599 573 #define BCM7XXX_40NM_EPHY(_oui, _name) \