diff mbox

[v3,3/5] net: phy: Add Broadcom phy library for common interfaces

Message ID 1444159550-3432-4-git-send-email-arunp@broadcom.com
State Accepted, archived
Delegated to: David Miller
Headers show

Commit Message

Arun Parameswaran Oct. 6, 2015, 7:25 p.m. UTC
This patch adds the Broadcom phy library to consolidate common
interfaces shared by Broadcom phy's.

Moved the common interfaces to the 'bcm-phy-lib.c' and updated
the Broadcom PHY drivers to use the new APIs.

Signed-off-by: Arun Parameswaran <arunp@broadcom.com>
---
 drivers/net/phy/Kconfig       |   6 ++
 drivers/net/phy/Makefile      |   1 +
 drivers/net/phy/bcm-phy-lib.c | 209 ++++++++++++++++++++++++++++++++++++++++++
 drivers/net/phy/bcm-phy-lib.h |  37 ++++++++
 drivers/net/phy/bcm63xx.c     |  38 +-------
 drivers/net/phy/bcm7xxx.c     | 127 ++++++-------------------
 drivers/net/phy/broadcom.c    | 149 +++++++++---------------------
 include/linux/brcmphy.h       |  22 +----
 8 files changed, 333 insertions(+), 256 deletions(-)
 create mode 100644 drivers/net/phy/bcm-phy-lib.c
 create mode 100644 drivers/net/phy/bcm-phy-lib.h

Comments

Robert E Cochran Oct. 14, 2015, 5:33 p.m. UTC | #1
On 10/06/2015 03:25 PM, Arun Parameswaran wrote:
> This patch adds the Broadcom phy library to consolidate common
> interfaces shared by Broadcom phy's.

The BCM54612E is included in the Broadcom Community part portfolio 
(https://community.broadcom.com).  However, I don't see this part 
explicitly supported by your phy library ( e.g., not included in 
broadcom_drivers[] in broadcom.c ).

Can you please comment on whether this part is supported or the extent 
of changes required to establish and support a robust GigE connection 
between RGMII and CU?

We're considering this part for a new embedded design, and we need an 
open source driver for it.

Thanks

Bob



>
> Moved the common interfaces to the 'bcm-phy-lib.c' and updated
> the Broadcom PHY drivers to use the new APIs.
>
> Signed-off-by: Arun Parameswaran <arunp@broadcom.com>
> ---
>   drivers/net/phy/Kconfig       |   6 ++
>   drivers/net/phy/Makefile      |   1 +
>   drivers/net/phy/bcm-phy-lib.c | 209 ++++++++++++++++++++++++++++++++++++++++++
>   drivers/net/phy/bcm-phy-lib.h |  37 ++++++++
>   drivers/net/phy/bcm63xx.c     |  38 +-------
>   drivers/net/phy/bcm7xxx.c     | 127 ++++++-------------------
>   drivers/net/phy/broadcom.c    | 149 +++++++++---------------------
>   include/linux/brcmphy.h       |  22 +----
>   8 files changed, 333 insertions(+), 256 deletions(-)
>   create mode 100644 drivers/net/phy/bcm-phy-lib.c
>   create mode 100644 drivers/net/phy/bcm-phy-lib.h
>
> diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
> index b57f6c2..606fdc9 100644
> --- a/drivers/net/phy/Kconfig
> +++ b/drivers/net/phy/Kconfig
> @@ -69,8 +69,12 @@ config SMSC_PHY
>   	---help---
>   	  Currently supports the LAN83C185, LAN8187 and LAN8700 PHYs
>   
> +config BCM_NET_PHYLIB
> +	tristate
> +
>   config BROADCOM_PHY
>   	tristate "Drivers for Broadcom PHYs"
> +	select BCM_NET_PHYLIB
>   	---help---
>   	  Currently supports the BCM5411, BCM5421, BCM5461, BCM54616S, BCM5464,
>   	  BCM5481 and BCM5482 PHYs.
> @@ -78,11 +82,13 @@ config BROADCOM_PHY
>   config BCM63XX_PHY
>   	tristate "Drivers for Broadcom 63xx SOCs internal PHY"
>   	depends on BCM63XX
> +	select BCM_NET_PHYLIB
>   	---help---
>   	  Currently supports the 6348 and 6358 PHYs.
>   
>   config BCM7XXX_PHY
>   	tristate "Drivers for Broadcom 7xxx SOCs internal PHYs"
> +	select BCM_NET_PHYLIB
>   	---help---
>   	  Currently supports the BCM7366, BCM7439, BCM7445, and
>   	  40nm and 65nm generation of BCM7xxx Set Top Box SoCs.
> diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
> index f4e6eb9..6932475 100644
> --- a/drivers/net/phy/Makefile
> +++ b/drivers/net/phy/Makefile
> @@ -12,6 +12,7 @@ obj-$(CONFIG_QSEMI_PHY)		+= qsemi.o
>   obj-$(CONFIG_SMSC_PHY)		+= smsc.o
>   obj-$(CONFIG_TERANETICS_PHY)	+= teranetics.o
>   obj-$(CONFIG_VITESSE_PHY)	+= vitesse.o
> +obj-$(CONFIG_BCM_NET_PHYLIB)	+= bcm-phy-lib.o
>   obj-$(CONFIG_BROADCOM_PHY)	+= broadcom.o
>   obj-$(CONFIG_BCM63XX_PHY)	+= bcm63xx.o
>   obj-$(CONFIG_BCM7XXX_PHY)	+= bcm7xxx.o
> diff --git a/drivers/net/phy/bcm-phy-lib.c b/drivers/net/phy/bcm-phy-lib.c
> new file mode 100644
> index 0000000..13e161e
> --- /dev/null
> +++ b/drivers/net/phy/bcm-phy-lib.c
> @@ -0,0 +1,209 @@
> +/*
> + * Copyright (C) 2015 Broadcom Corporation
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation version 2.
> + *
> + * This program is distributed "as is" WITHOUT ANY WARRANTY of any
> + * kind, whether express or implied; without even the implied warranty
> + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#include "bcm-phy-lib.h"
> +#include <linux/brcmphy.h>
> +#include <linux/export.h>
> +#include <linux/mdio.h>
> +#include <linux/phy.h>
> +
> +#define MII_BCM_CHANNEL_WIDTH     0x2000
> +#define BCM_CL45VEN_EEE_ADV       0x3c
> +
> +int bcm_phy_write_exp(struct phy_device *phydev, u16 reg, u16 val)
> +{
> +	int rc;
> +
> +	rc = phy_write(phydev, MII_BCM54XX_EXP_SEL, reg);
> +	if (rc < 0)
> +		return rc;
> +
> +	return phy_write(phydev, MII_BCM54XX_EXP_DATA, val);
> +}
> +EXPORT_SYMBOL_GPL(bcm_phy_write_exp);
> +
> +int bcm_phy_read_exp(struct phy_device *phydev, u16 reg)
> +{
> +	int val;
> +
> +	val = phy_write(phydev, MII_BCM54XX_EXP_SEL, reg);
> +	if (val < 0)
> +		return val;
> +
> +	val = phy_read(phydev, MII_BCM54XX_EXP_DATA);
> +
> +	/* Restore default value.  It's O.K. if this write fails. */
> +	phy_write(phydev, MII_BCM54XX_EXP_SEL, 0);
> +
> +	return val;
> +}
> +EXPORT_SYMBOL_GPL(bcm_phy_read_exp);
> +
> +int bcm_phy_write_misc(struct phy_device *phydev,
> +		       u16 reg, u16 chl, u16 val)
> +{
> +	int rc;
> +	int tmp;
> +
> +	rc = phy_write(phydev, MII_BCM54XX_AUX_CTL,
> +		       MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
> +	if (rc < 0)
> +		return rc;
> +
> +	tmp = phy_read(phydev, MII_BCM54XX_AUX_CTL);
> +	tmp |= MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA;
> +	rc = phy_write(phydev, MII_BCM54XX_AUX_CTL, tmp);
> +	if (rc < 0)
> +		return rc;
> +
> +	tmp = (chl * MII_BCM_CHANNEL_WIDTH) | reg;
> +	rc = bcm_phy_write_exp(phydev, tmp, val);
> +
> +	return rc;
> +}
> +EXPORT_SYMBOL_GPL(bcm_phy_write_misc);
> +
> +int bcm_phy_read_misc(struct phy_device *phydev,
> +		      u16 reg, u16 chl)
> +{
> +	int rc;
> +	int tmp;
> +
> +	rc = phy_write(phydev, MII_BCM54XX_AUX_CTL,
> +		       MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
> +	if (rc < 0)
> +		return rc;
> +
> +	tmp = phy_read(phydev, MII_BCM54XX_AUX_CTL);
> +	tmp |= MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA;
> +	rc = phy_write(phydev, MII_BCM54XX_AUX_CTL, tmp);
> +	if (rc < 0)
> +		return rc;
> +
> +	tmp = (chl * MII_BCM_CHANNEL_WIDTH) | reg;
> +	rc = bcm_phy_read_exp(phydev, tmp);
> +
> +	return rc;
> +}
> +EXPORT_SYMBOL_GPL(bcm_phy_read_misc);
> +
> +int bcm_phy_ack_intr(struct phy_device *phydev)
> +{
> +	int reg;
> +
> +	/* Clear pending interrupts.  */
> +	reg = phy_read(phydev, MII_BCM54XX_ISR);
> +	if (reg < 0)
> +		return reg;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(bcm_phy_ack_intr);
> +
> +int bcm_phy_config_intr(struct phy_device *phydev)
> +{
> +	int reg;
> +
> +	reg = phy_read(phydev, MII_BCM54XX_ECR);
> +	if (reg < 0)
> +		return reg;
> +
> +	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
> +		reg &= ~MII_BCM54XX_ECR_IM;
> +	else
> +		reg |= MII_BCM54XX_ECR_IM;
> +
> +	return phy_write(phydev, MII_BCM54XX_ECR, reg);
> +}
> +EXPORT_SYMBOL_GPL(bcm_phy_config_intr);
> +
> +int bcm_phy_read_shadow(struct phy_device *phydev, u16 shadow)
> +{
> +	phy_write(phydev, MII_BCM54XX_SHD, MII_BCM54XX_SHD_VAL(shadow));
> +	return MII_BCM54XX_SHD_DATA(phy_read(phydev, MII_BCM54XX_SHD));
> +}
> +EXPORT_SYMBOL_GPL(bcm_phy_read_shadow);
> +
> +int bcm_phy_write_shadow(struct phy_device *phydev, u16 shadow,
> +			 u16 val)
> +{
> +	return phy_write(phydev, MII_BCM54XX_SHD,
> +			 MII_BCM54XX_SHD_WRITE |
> +			 MII_BCM54XX_SHD_VAL(shadow) |
> +			 MII_BCM54XX_SHD_DATA(val));
> +}
> +EXPORT_SYMBOL_GPL(bcm_phy_write_shadow);
> +
> +int bcm_phy_enable_apd(struct phy_device *phydev, bool dll_pwr_down)
> +{
> +	int val;
> +
> +	if (dll_pwr_down) {
> +		val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR3);
> +		if (val < 0)
> +			return val;
> +
> +		val |= BCM54XX_SHD_SCR3_DLLAPD_DIS;
> +		bcm_phy_write_shadow(phydev, BCM54XX_SHD_SCR3, val);
> +	}
> +
> +	val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_APD);
> +	if (val < 0)
> +		return val;
> +
> +	/* Clear APD bits */
> +	val &= BCM_APD_CLR_MASK;
> +
> +	if (phydev->autoneg == AUTONEG_ENABLE)
> +		val |= BCM54XX_SHD_APD_EN;
> +	else
> +		val |= BCM_NO_ANEG_APD_EN;
> +
> +	/* Enable energy detect single link pulse for easy wakeup */
> +	val |= BCM_APD_SINGLELP_EN;
> +
> +	/* Enable Auto Power-Down (APD) for the PHY */
> +	return bcm_phy_write_shadow(phydev, BCM54XX_SHD_APD, val);
> +}
> +EXPORT_SYMBOL_GPL(bcm_phy_enable_apd);
> +
> +int bcm_phy_enable_eee(struct phy_device *phydev)
> +{
> +	int val;
> +
> +	/* Enable EEE at PHY level */
> +	val = phy_read_mmd_indirect(phydev, BRCM_CL45VEN_EEE_CONTROL,
> +				    MDIO_MMD_AN, phydev->addr);
> +	if (val < 0)
> +		return val;
> +
> +	val |= LPI_FEATURE_EN | LPI_FEATURE_EN_DIG1000X;
> +
> +	phy_write_mmd_indirect(phydev, BRCM_CL45VEN_EEE_CONTROL,
> +			       MDIO_MMD_AN,  phydev->addr, (u32)val);
> +
> +	/* Advertise EEE */
> +	val = phy_read_mmd_indirect(phydev, BCM_CL45VEN_EEE_ADV,
> +				    MDIO_MMD_AN, phydev->addr);
> +	if (val < 0)
> +		return val;
> +
> +	val |= (MDIO_AN_EEE_ADV_100TX | MDIO_AN_EEE_ADV_1000T);
> +
> +	phy_write_mmd_indirect(phydev, BCM_CL45VEN_EEE_ADV,
> +			       MDIO_MMD_AN,  phydev->addr, (u32)val);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(bcm_phy_enable_eee);
> +
> diff --git a/drivers/net/phy/bcm-phy-lib.h b/drivers/net/phy/bcm-phy-lib.h
> new file mode 100644
> index 0000000..b2091c8
> --- /dev/null
> +++ b/drivers/net/phy/bcm-phy-lib.h
> @@ -0,0 +1,37 @@
> +/*
> + * Copyright (C) 2015 Broadcom Corporation
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation version 2.
> + *
> + * This program is distributed "as is" WITHOUT ANY WARRANTY of any
> + * kind, whether express or implied; without even the implied warranty
> + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#ifndef _LINUX_BCM_PHY_LIB_H
> +#define _LINUX_BCM_PHY_LIB_H
> +
> +#include <linux/phy.h>
> +
> +int bcm_phy_write_exp(struct phy_device *phydev, u16 reg, u16 val);
> +int bcm_phy_read_exp(struct phy_device *phydev, u16 reg);
> +
> +int bcm_phy_write_misc(struct phy_device *phydev,
> +		       u16 reg, u16 chl, u16 value);
> +int bcm_phy_read_misc(struct phy_device *phydev,
> +		      u16 reg, u16 chl);
> +
> +int bcm_phy_write_shadow(struct phy_device *phydev, u16 shadow,
> +			 u16 val);
> +int bcm_phy_read_shadow(struct phy_device *phydev, u16 shadow);
> +
> +int bcm_phy_ack_intr(struct phy_device *phydev);
> +int bcm_phy_config_intr(struct phy_device *phydev);
> +
> +int bcm_phy_enable_apd(struct phy_device *phydev, bool dll_pwr_down);
> +
> +int bcm_phy_enable_eee(struct phy_device *phydev);
> +#endif /* _LINUX_BCM_PHY_LIB_H */
> diff --git a/drivers/net/phy/bcm63xx.c b/drivers/net/phy/bcm63xx.c
> index 830ec31..86b2805 100644
> --- a/drivers/net/phy/bcm63xx.c
> +++ b/drivers/net/phy/bcm63xx.c
> @@ -6,6 +6,7 @@
>    *	as published by the Free Software Foundation; either version
>    *	2 of the License, or (at your option) any later version.
>    */
> +#include "bcm-phy-lib.h"
>   #include <linux/module.h>
>   #include <linux/phy.h>
>   
> @@ -42,35 +43,6 @@ static int bcm63xx_config_init(struct phy_device *phydev)
>   	return phy_write(phydev, MII_BCM63XX_IR, reg);
>   }
>   
> -static int bcm63xx_ack_interrupt(struct phy_device *phydev)
> -{
> -	int reg;
> -
> -	/* Clear pending interrupts.  */
> -	reg = phy_read(phydev, MII_BCM63XX_IR);
> -	if (reg < 0)
> -		return reg;
> -
> -	return 0;
> -}
> -
> -static int bcm63xx_config_intr(struct phy_device *phydev)
> -{
> -	int reg, err;
> -
> -	reg = phy_read(phydev, MII_BCM63XX_IR);
> -	if (reg < 0)
> -		return reg;
> -
> -	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
> -		reg &= ~MII_BCM63XX_IR_GMASK;
> -	else
> -		reg |= MII_BCM63XX_IR_GMASK;
> -
> -	err = phy_write(phydev, MII_BCM63XX_IR, reg);
> -	return err;
> -}
> -
>   static struct phy_driver bcm63xx_driver[] = {
>   {
>   	.phy_id		= 0x00406000,
> @@ -82,8 +54,8 @@ static struct phy_driver bcm63xx_driver[] = {
>   	.config_init	= bcm63xx_config_init,
>   	.config_aneg	= genphy_config_aneg,
>   	.read_status	= genphy_read_status,
> -	.ack_interrupt	= bcm63xx_ack_interrupt,
> -	.config_intr	= bcm63xx_config_intr,
> +	.ack_interrupt	= bcm_phy_ack_intr,
> +	.config_intr	= bcm_phy_config_intr,
>   	.driver		= { .owner = THIS_MODULE },
>   }, {
>   	/* same phy as above, with just a different OUI */
> @@ -95,8 +67,8 @@ static struct phy_driver bcm63xx_driver[] = {
>   	.config_init	= bcm63xx_config_init,
>   	.config_aneg	= genphy_config_aneg,
>   	.read_status	= genphy_read_status,
> -	.ack_interrupt	= bcm63xx_ack_interrupt,
> -	.config_intr	= bcm63xx_config_intr,
> +	.ack_interrupt	= bcm_phy_ack_intr,
> +	.config_intr	= bcm_phy_config_intr,
>   	.driver		= { .owner = THIS_MODULE },
>   } };
>   
> diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c
> index 6b701b3..efa31a6 100644
> --- a/drivers/net/phy/bcm7xxx.c
> +++ b/drivers/net/phy/bcm7xxx.c
> @@ -12,12 +12,12 @@
>   #include <linux/module.h>
>   #include <linux/phy.h>
>   #include <linux/delay.h>
> +#include "bcm-phy-lib.h"
>   #include <linux/bitops.h>
>   #include <linux/brcmphy.h>
>   #include <linux/mdio.h>
>   
>   /* Broadcom BCM7xxx internal PHY registers */
> -#define MII_BCM7XXX_CHANNEL_WIDTH	0x2000
>   
>   /* 40nm only register definitions */
>   #define MII_BCM7XXX_100TX_AUX_CTL	0x10
> @@ -48,37 +48,13 @@
>   
>   #define CORE_EXPB0			0xb0
>   
> -static void phy_write_exp(struct phy_device *phydev,
> -					u16 reg, u16 value)
> -{
> -	phy_write(phydev, MII_BCM54XX_EXP_SEL, MII_BCM54XX_EXP_SEL_ER | reg);
> -	phy_write(phydev, MII_BCM54XX_EXP_DATA, value);
> -}
> -
> -static void phy_write_misc(struct phy_device *phydev,
> -					u16 reg, u16 chl, u16 value)
> -{
> -	int tmp;
> -
> -	phy_write(phydev, MII_BCM54XX_AUX_CTL, MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
> -
> -	tmp = phy_read(phydev, MII_BCM54XX_AUX_CTL);
> -	tmp |= MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA;
> -	phy_write(phydev, MII_BCM54XX_AUX_CTL, tmp);
> -
> -	tmp = (chl * MII_BCM7XXX_CHANNEL_WIDTH) | reg;
> -	phy_write(phydev, MII_BCM54XX_EXP_SEL, tmp);
> -
> -	phy_write(phydev, MII_BCM54XX_EXP_DATA, value);
> -}
> -
>   static void r_rc_cal_reset(struct phy_device *phydev)
>   {
>   	/* Reset R_CAL/RC_CAL Engine */
> -	phy_write_exp(phydev, 0x00b0, 0x0010);
> +	bcm_phy_write_exp(phydev, 0x00b0, 0x0010);
>   
>   	/* Disable Reset R_AL/RC_CAL Engine */
> -	phy_write_exp(phydev, 0x00b0, 0x0000);
> +	bcm_phy_write_exp(phydev, 0x00b0, 0x0000);
>   }
>   
>   static int bcm7xxx_28nm_b0_afe_config_init(struct phy_device *phydev)
> @@ -86,18 +62,18 @@ static int bcm7xxx_28nm_b0_afe_config_init(struct phy_device *phydev)
>   	/* Increase VCO range to prevent unlocking problem of PLL at low
>   	 * temp
>   	 */
> -	phy_write_misc(phydev, PLL_PLLCTRL_1, 0x0048);
> +	bcm_phy_write_misc(phydev, PLL_PLLCTRL_1, 0x0048);
>   
>   	/* Change Ki to 011 */
> -	phy_write_misc(phydev, PLL_PLLCTRL_2, 0x021b);
> +	bcm_phy_write_misc(phydev, PLL_PLLCTRL_2, 0x021b);
>   
>   	/* Disable loading of TVCO buffer to bandgap, set bandgap trim
>   	 * to 111
>   	 */
> -	phy_write_misc(phydev, PLL_PLLCTRL_4, 0x0e20);
> +	bcm_phy_write_misc(phydev, PLL_PLLCTRL_4, 0x0e20);
>   
>   	/* Adjust bias current trim by -3 */
> -	phy_write_misc(phydev, DSP_TAP10, 0x690b);
> +	bcm_phy_write_misc(phydev, DSP_TAP10, 0x690b);
>   
>   	/* Switch to CORE_BASE1E */
>   	phy_write(phydev, MII_BCM7XXX_CORE_BASE1E, 0xd);
> @@ -105,19 +81,19 @@ static int bcm7xxx_28nm_b0_afe_config_init(struct phy_device *phydev)
>   	r_rc_cal_reset(phydev);
>   
>   	/* write AFE_RXCONFIG_0 */
> -	phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb19);
> +	bcm_phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb19);
>   
>   	/* write AFE_RXCONFIG_1 */
> -	phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9a3f);
> +	bcm_phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9a3f);
>   
>   	/* write AFE_RX_LP_COUNTER */
> -	phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0);
> +	bcm_phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0);
>   
>   	/* write AFE_HPF_TRIM_OTHERS */
> -	phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x000b);
> +	bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x000b);
>   
>   	/* write AFTE_TX_CONFIG */
> -	phy_write_misc(phydev, AFE_TX_CONFIG, 0x0800);
> +	bcm_phy_write_misc(phydev, AFE_TX_CONFIG, 0x0800);
>   
>   	return 0;
>   }
> @@ -125,36 +101,36 @@ static int bcm7xxx_28nm_b0_afe_config_init(struct phy_device *phydev)
>   static int bcm7xxx_28nm_d0_afe_config_init(struct phy_device *phydev)
>   {
>   	/* AFE_RXCONFIG_0 */
> -	phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb15);
> +	bcm_phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb15);
>   
>   	/* AFE_RXCONFIG_1 */
> -	phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9b2f);
> +	bcm_phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9b2f);
>   
>   	/* AFE_RXCONFIG_2, set rCal offset for HT=0 code and LT=-2 code */
> -	phy_write_misc(phydev, AFE_RXCONFIG_2, 0x2003);
> +	bcm_phy_write_misc(phydev, AFE_RXCONFIG_2, 0x2003);
>   
>   	/* AFE_RX_LP_COUNTER, set RX bandwidth to maximum */
> -	phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0);
> +	bcm_phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0);
>   
>   	/* AFE_TX_CONFIG, set 100BT Cfeed=011 to improve rise/fall time */
> -	phy_write_misc(phydev, AFE_TX_CONFIG, 0x431);
> +	bcm_phy_write_misc(phydev, AFE_TX_CONFIG, 0x431);
>   
>   	/* AFE_VDCA_ICTRL_0, set Iq=1101 instead of 0111 for AB symmetry */
> -	phy_write_misc(phydev, AFE_VDCA_ICTRL_0, 0xa7da);
> +	bcm_phy_write_misc(phydev, AFE_VDCA_ICTRL_0, 0xa7da);
>   
>   	/* AFE_VDAC_OTHERS_0, set 1000BT Cidac=010 for all ports */
> -	phy_write_misc(phydev, AFE_VDAC_OTHERS_0, 0xa020);
> +	bcm_phy_write_misc(phydev, AFE_VDAC_OTHERS_0, 0xa020);
>   
>   	/* AFE_HPF_TRIM_OTHERS, set 100Tx/10BT to -4.5% swing and set rCal
>   	 * offset for HT=0 code
>   	 */
> -	phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x00e3);
> +	bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x00e3);
>   
>   	/* CORE_BASE1E, force trim to overwrite and set I_ext trim to 0000 */
>   	phy_write(phydev, MII_BCM7XXX_CORE_BASE1E, 0x0010);
>   
>   	/* DSP_TAP10, adjust bias current trim (+0% swing, +0 tick) */
> -	phy_write_misc(phydev, DSP_TAP10, 0x011b);
> +	bcm_phy_write_misc(phydev, DSP_TAP10, 0x011b);
>   
>   	/* Reset R_CAL/RC_CAL engine */
>   	r_rc_cal_reset(phydev);
> @@ -165,24 +141,24 @@ static int bcm7xxx_28nm_d0_afe_config_init(struct phy_device *phydev)
>   static int bcm7xxx_28nm_e0_plus_afe_config_init(struct phy_device *phydev)
>   {
>   	/* AFE_RXCONFIG_1, provide more margin for INL/DNL measurement */
> -	phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9b2f);
> +	bcm_phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9b2f);
>   
>   	/* AFE_TX_CONFIG, set 100BT Cfeed=011 to improve rise/fall time */
> -	phy_write_misc(phydev, AFE_TX_CONFIG, 0x431);
> +	bcm_phy_write_misc(phydev, AFE_TX_CONFIG, 0x431);
>   
>   	/* AFE_VDCA_ICTRL_0, set Iq=1101 instead of 0111 for AB symmetry */
> -	phy_write_misc(phydev, AFE_VDCA_ICTRL_0, 0xa7da);
> +	bcm_phy_write_misc(phydev, AFE_VDCA_ICTRL_0, 0xa7da);
>   
>   	/* AFE_HPF_TRIM_OTHERS, set 100Tx/10BT to -4.5% swing and set rCal
>   	 * offset for HT=0 code
>   	 */
> -	phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x00e3);
> +	bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x00e3);
>   
>   	/* CORE_BASE1E, force trim to overwrite and set I_ext trim to 0000 */
>   	phy_write(phydev, MII_BCM7XXX_CORE_BASE1E, 0x0010);
>   
>   	/* DSP_TAP10, adjust bias current trim (+0% swing, +0 tick) */
> -	phy_write_misc(phydev, DSP_TAP10, 0x011b);
> +	bcm_phy_write_misc(phydev, DSP_TAP10, 0x011b);
>   
>   	/* Reset R_CAL/RC_CAL engine */
>   	r_rc_cal_reset(phydev);
> @@ -190,53 +166,6 @@ static int bcm7xxx_28nm_e0_plus_afe_config_init(struct phy_device *phydev)
>   	return 0;
>   }
>   
> -static int bcm7xxx_apd_enable(struct phy_device *phydev)
> -{
> -	int val;
> -
> -	/* Enable powering down of the DLL during auto-power down */
> -	val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_SCR3);
> -	if (val < 0)
> -		return val;
> -
> -	val |= BCM54XX_SHD_SCR3_DLLAPD_DIS;
> -	bcm54xx_shadow_write(phydev, BCM54XX_SHD_SCR3, val);
> -
> -	/* Enable auto-power down */
> -	val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_APD);
> -	if (val < 0)
> -		return val;
> -
> -	val |= BCM54XX_SHD_APD_EN;
> -	return bcm54xx_shadow_write(phydev, BCM54XX_SHD_APD, val);
> -}
> -
> -static int bcm7xxx_eee_enable(struct phy_device *phydev)
> -{
> -	int val;
> -
> -	val = phy_read_mmd_indirect(phydev, BRCM_CL45VEN_EEE_CONTROL,
> -				    MDIO_MMD_AN, phydev->addr);
> -	if (val < 0)
> -		return val;
> -
> -	/* Enable general EEE feature at the PHY level */
> -	val |= LPI_FEATURE_EN | LPI_FEATURE_EN_DIG1000X;
> -
> -	phy_write_mmd_indirect(phydev, BRCM_CL45VEN_EEE_CONTROL,
> -			       MDIO_MMD_AN, phydev->addr, val);
> -
> -	/* Advertise supported modes */
> -	val = phy_read_mmd_indirect(phydev, MDIO_AN_EEE_ADV,
> -				    MDIO_MMD_AN, phydev->addr);
> -
> -	val |= (MDIO_AN_EEE_ADV_100TX | MDIO_AN_EEE_ADV_1000T);
> -	phy_write_mmd_indirect(phydev, MDIO_AN_EEE_ADV,
> -			       MDIO_MMD_AN, phydev->addr, val);
> -
> -	return 0;
> -}
> -
>   static int bcm7xxx_28nm_config_init(struct phy_device *phydev)
>   {
>   	u8 rev = PHY_BRCM_7XXX_REV(phydev->dev_flags);
> @@ -273,11 +202,11 @@ static int bcm7xxx_28nm_config_init(struct phy_device *phydev)
>   	if (ret)
>   		return ret;
>   
> -	ret = bcm7xxx_eee_enable(phydev);
> +	ret = bcm_phy_enable_eee(phydev);
>   	if (ret)
>   		return ret;
>   
> -	return bcm7xxx_apd_enable(phydev);
> +	return bcm_phy_enable_apd(phydev, true);
>   }
>   
>   static int bcm7xxx_28nm_resume(struct phy_device *phydev)
> diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
> index 9c71295..07a6119 100644
> --- a/drivers/net/phy/broadcom.c
> +++ b/drivers/net/phy/broadcom.c
> @@ -14,6 +14,7 @@
>    *	2 of the License, or (at your option) any later version.
>    */
>   
> +#include "bcm-phy-lib.h"
>   #include <linux/module.h>
>   #include <linux/phy.h>
>   #include <linux/brcmphy.h>
> @@ -29,39 +30,6 @@ MODULE_DESCRIPTION("Broadcom PHY driver");
>   MODULE_AUTHOR("Maciej W. Rozycki");
>   MODULE_LICENSE("GPL");
>   
> -/* Indirect register access functions for the Expansion Registers */
> -static int bcm54xx_exp_read(struct phy_device *phydev, u16 regnum)
> -{
> -	int val;
> -
> -	val = phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum);
> -	if (val < 0)
> -		return val;
> -
> -	val = phy_read(phydev, MII_BCM54XX_EXP_DATA);
> -
> -	/* Restore default value.  It's O.K. if this write fails. */
> -	phy_write(phydev, MII_BCM54XX_EXP_SEL, 0);
> -
> -	return val;
> -}
> -
> -static int bcm54xx_exp_write(struct phy_device *phydev, u16 regnum, u16 val)
> -{
> -	int ret;
> -
> -	ret = phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum);
> -	if (ret < 0)
> -		return ret;
> -
> -	ret = phy_write(phydev, MII_BCM54XX_EXP_DATA, val);
> -
> -	/* Restore default value.  It's O.K. if this write fails. */
> -	phy_write(phydev, MII_BCM54XX_EXP_SEL, 0);
> -
> -	return ret;
> -}
> -
>   static int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val)
>   {
>   	return phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum | val);
> @@ -72,28 +40,28 @@ static int bcm50610_a0_workaround(struct phy_device *phydev)
>   {
>   	int err;
>   
> -	err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH0,
> +	err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_AADJ1CH0,
>   				MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN |
>   				MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF);
>   	if (err < 0)
>   		return err;
>   
> -	err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH3,
> -					MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ);
> +	err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_AADJ1CH3,
> +				MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ);
>   	if (err < 0)
>   		return err;
>   
> -	err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP75,
> +	err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP75,
>   				MII_BCM54XX_EXP_EXP75_VDACCTRL);
>   	if (err < 0)
>   		return err;
>   
> -	err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP96,
> +	err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP96,
>   				MII_BCM54XX_EXP_EXP96_MYST);
>   	if (err < 0)
>   		return err;
>   
> -	err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP97,
> +	err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP97,
>   				MII_BCM54XX_EXP_EXP97_MYST);
>   
>   	return err;
> @@ -114,7 +82,7 @@ static int bcm54xx_phydsp_config(struct phy_device *phydev)
>   	if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
>   	    BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) {
>   		/* Clear bit 9 to fix a phy interop issue. */
> -		err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP08,
> +		err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP08,
>   					MII_BCM54XX_EXP_EXP08_RJCT_2MHZ);
>   		if (err < 0)
>   			goto error;
> @@ -129,12 +97,12 @@ static int bcm54xx_phydsp_config(struct phy_device *phydev)
>   	if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM57780) {
>   		int val;
>   
> -		val = bcm54xx_exp_read(phydev, MII_BCM54XX_EXP_EXP75);
> +		val = bcm_phy_read_exp(phydev, MII_BCM54XX_EXP_EXP75);
>   		if (val < 0)
>   			goto error;
>   
>   		val |= MII_BCM54XX_EXP_EXP75_CM_OSC;
> -		err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP75, val);
> +		err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP75, val);
>   	}
>   
>   error:
> @@ -159,7 +127,7 @@ static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev)
>   	    BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610M)
>   		return;
>   
> -	val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_SCR3);
> +	val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR3);
>   	if (val < 0)
>   		return;
>   
> @@ -190,9 +158,9 @@ static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev)
>   		val |= BCM54XX_SHD_SCR3_TRDDAPD;
>   
>   	if (orig != val)
> -		bcm54xx_shadow_write(phydev, BCM54XX_SHD_SCR3, val);
> +		bcm_phy_write_shadow(phydev, BCM54XX_SHD_SCR3, val);
>   
> -	val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_APD);
> +	val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_APD);
>   	if (val < 0)
>   		return;
>   
> @@ -204,7 +172,7 @@ static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev)
>   		val &= ~BCM54XX_SHD_APD_EN;
>   
>   	if (orig != val)
> -		bcm54xx_shadow_write(phydev, BCM54XX_SHD_APD, val);
> +		bcm_phy_write_shadow(phydev, BCM54XX_SHD_APD, val);
>   }
>   
>   static int bcm54xx_config_init(struct phy_device *phydev)
> @@ -232,7 +200,7 @@ static int bcm54xx_config_init(struct phy_device *phydev)
>   	if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
>   	     BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) &&
>   	    (phydev->dev_flags & PHY_BRCM_CLEAR_RGMII_MODE))
> -		bcm54xx_shadow_write(phydev, BCM54XX_SHD_RGMII_MODE, 0);
> +		bcm_phy_write_shadow(phydev, BCM54XX_SHD_RGMII_MODE, 0);
>   
>   	if ((phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) ||
>   	    (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY) ||
> @@ -254,8 +222,8 @@ static int bcm5482_config_init(struct phy_device *phydev)
>   		/*
>   		 * Enable secondary SerDes and its use as an LED source
>   		 */
> -		reg = bcm54xx_shadow_read(phydev, BCM5482_SHD_SSD);
> -		bcm54xx_shadow_write(phydev, BCM5482_SHD_SSD,
> +		reg = bcm_phy_read_shadow(phydev, BCM5482_SHD_SSD);
> +		bcm_phy_write_shadow(phydev, BCM5482_SHD_SSD,
>   				     reg |
>   				     BCM5482_SHD_SSD_LEDM |
>   				     BCM5482_SHD_SSD_EN);
> @@ -264,10 +232,10 @@ static int bcm5482_config_init(struct phy_device *phydev)
>   		 * Enable SGMII slave mode and auto-detection
>   		 */
>   		reg = BCM5482_SSD_SGMII_SLAVE | MII_BCM54XX_EXP_SEL_SSD;
> -		err = bcm54xx_exp_read(phydev, reg);
> +		err = bcm_phy_read_exp(phydev, reg);
>   		if (err < 0)
>   			return err;
> -		err = bcm54xx_exp_write(phydev, reg, err |
> +		err = bcm_phy_write_exp(phydev, reg, err |
>   					BCM5482_SSD_SGMII_SLAVE_EN |
>   					BCM5482_SSD_SGMII_SLAVE_AD);
>   		if (err < 0)
> @@ -277,10 +245,10 @@ static int bcm5482_config_init(struct phy_device *phydev)
>   		 * Disable secondary SerDes powerdown
>   		 */
>   		reg = BCM5482_SSD_1000BX_CTL | MII_BCM54XX_EXP_SEL_SSD;
> -		err = bcm54xx_exp_read(phydev, reg);
> +		err = bcm_phy_read_exp(phydev, reg);
>   		if (err < 0)
>   			return err;
> -		err = bcm54xx_exp_write(phydev, reg,
> +		err = bcm_phy_write_exp(phydev, reg,
>   					err & ~BCM5482_SSD_1000BX_CTL_PWRDOWN);
>   		if (err < 0)
>   			return err;
> @@ -288,15 +256,15 @@ static int bcm5482_config_init(struct phy_device *phydev)
>   		/*
>   		 * Select 1000BASE-X register set (primary SerDes)
>   		 */
> -		reg = bcm54xx_shadow_read(phydev, BCM5482_SHD_MODE);
> -		bcm54xx_shadow_write(phydev, BCM5482_SHD_MODE,
> +		reg = bcm_phy_read_shadow(phydev, BCM5482_SHD_MODE);
> +		bcm_phy_write_shadow(phydev, BCM5482_SHD_MODE,
>   				     reg | BCM5482_SHD_MODE_1000BX);
>   
>   		/*
>   		 * LED1=ACTIVITYLED, LED3=LINKSPD[2]
>   		 * (Use LED1 as secondary SerDes ACTIVITY LED)
>   		 */
> -		bcm54xx_shadow_write(phydev, BCM5482_SHD_LEDS1,
> +		bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1,
>   			BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_ACTIVITYLED) |
>   			BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_LINKSPD2));
>   
> @@ -334,35 +302,6 @@ static int bcm5482_read_status(struct phy_device *phydev)
>   	return err;
>   }
>   
> -static int bcm54xx_ack_interrupt(struct phy_device *phydev)
> -{
> -	int reg;
> -
> -	/* Clear pending interrupts.  */
> -	reg = phy_read(phydev, MII_BCM54XX_ISR);
> -	if (reg < 0)
> -		return reg;
> -
> -	return 0;
> -}
> -
> -static int bcm54xx_config_intr(struct phy_device *phydev)
> -{
> -	int reg, err;
> -
> -	reg = phy_read(phydev, MII_BCM54XX_ECR);
> -	if (reg < 0)
> -		return reg;
> -
> -	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
> -		reg &= ~MII_BCM54XX_ECR_IM;
> -	else
> -		reg |= MII_BCM54XX_ECR_IM;
> -
> -	err = phy_write(phydev, MII_BCM54XX_ECR, reg);
> -	return err;
> -}
> -
>   static int bcm5481_config_aneg(struct phy_device *phydev)
>   {
>   	int ret;
> @@ -519,8 +458,8 @@ static struct phy_driver broadcom_drivers[] = {
>   	.config_init	= bcm54xx_config_init,
>   	.config_aneg	= genphy_config_aneg,
>   	.read_status	= genphy_read_status,
> -	.ack_interrupt	= bcm54xx_ack_interrupt,
> -	.config_intr	= bcm54xx_config_intr,
> +	.ack_interrupt	= bcm_phy_ack_intr,
> +	.config_intr	= bcm_phy_config_intr,
>   	.driver		= { .owner = THIS_MODULE },
>   }, {
>   	.phy_id		= PHY_ID_BCM5421,
> @@ -532,8 +471,8 @@ static struct phy_driver broadcom_drivers[] = {
>   	.config_init	= bcm54xx_config_init,
>   	.config_aneg	= genphy_config_aneg,
>   	.read_status	= genphy_read_status,
> -	.ack_interrupt	= bcm54xx_ack_interrupt,
> -	.config_intr	= bcm54xx_config_intr,
> +	.ack_interrupt	= bcm_phy_ack_intr,
> +	.config_intr	= bcm_phy_config_intr,
>   	.driver		= { .owner = THIS_MODULE },
>   }, {
>   	.phy_id		= PHY_ID_BCM5461,
> @@ -545,8 +484,8 @@ static struct phy_driver broadcom_drivers[] = {
>   	.config_init	= bcm54xx_config_init,
>   	.config_aneg	= genphy_config_aneg,
>   	.read_status	= genphy_read_status,
> -	.ack_interrupt	= bcm54xx_ack_interrupt,
> -	.config_intr	= bcm54xx_config_intr,
> +	.ack_interrupt	= bcm_phy_ack_intr,
> +	.config_intr	= bcm_phy_config_intr,
>   	.driver		= { .owner = THIS_MODULE },
>   }, {
>   	.phy_id		= PHY_ID_BCM54616S,
> @@ -558,8 +497,8 @@ static struct phy_driver broadcom_drivers[] = {
>   	.config_init	= bcm54xx_config_init,
>   	.config_aneg	= genphy_config_aneg,
>   	.read_status	= genphy_read_status,
> -	.ack_interrupt	= bcm54xx_ack_interrupt,
> -	.config_intr	= bcm54xx_config_intr,
> +	.ack_interrupt	= bcm_phy_ack_intr,
> +	.config_intr	= bcm_phy_config_intr,
>   	.driver		= { .owner = THIS_MODULE },
>   }, {
>   	.phy_id		= PHY_ID_BCM5464,
> @@ -571,8 +510,8 @@ static struct phy_driver broadcom_drivers[] = {
>   	.config_init	= bcm54xx_config_init,
>   	.config_aneg	= genphy_config_aneg,
>   	.read_status	= genphy_read_status,
> -	.ack_interrupt	= bcm54xx_ack_interrupt,
> -	.config_intr	= bcm54xx_config_intr,
> +	.ack_interrupt	= bcm_phy_ack_intr,
> +	.config_intr	= bcm_phy_config_intr,
>   	.driver		= { .owner = THIS_MODULE },
>   }, {
>   	.phy_id		= PHY_ID_BCM5481,
> @@ -584,8 +523,8 @@ static struct phy_driver broadcom_drivers[] = {
>   	.config_init	= bcm54xx_config_init,
>   	.config_aneg	= bcm5481_config_aneg,
>   	.read_status	= genphy_read_status,
> -	.ack_interrupt	= bcm54xx_ack_interrupt,
> -	.config_intr	= bcm54xx_config_intr,
> +	.ack_interrupt	= bcm_phy_ack_intr,
> +	.config_intr	= bcm_phy_config_intr,
>   	.driver		= { .owner = THIS_MODULE },
>   }, {
>   	.phy_id		= PHY_ID_BCM5482,
> @@ -597,8 +536,8 @@ static struct phy_driver broadcom_drivers[] = {
>   	.config_init	= bcm5482_config_init,
>   	.config_aneg	= genphy_config_aneg,
>   	.read_status	= bcm5482_read_status,
> -	.ack_interrupt	= bcm54xx_ack_interrupt,
> -	.config_intr	= bcm54xx_config_intr,
> +	.ack_interrupt	= bcm_phy_ack_intr,
> +	.config_intr	= bcm_phy_config_intr,
>   	.driver		= { .owner = THIS_MODULE },
>   }, {
>   	.phy_id		= PHY_ID_BCM50610,
> @@ -610,8 +549,8 @@ static struct phy_driver broadcom_drivers[] = {
>   	.config_init	= bcm54xx_config_init,
>   	.config_aneg	= genphy_config_aneg,
>   	.read_status	= genphy_read_status,
> -	.ack_interrupt	= bcm54xx_ack_interrupt,
> -	.config_intr	= bcm54xx_config_intr,
> +	.ack_interrupt	= bcm_phy_ack_intr,
> +	.config_intr	= bcm_phy_config_intr,
>   	.driver		= { .owner = THIS_MODULE },
>   }, {
>   	.phy_id		= PHY_ID_BCM50610M,
> @@ -623,8 +562,8 @@ static struct phy_driver broadcom_drivers[] = {
>   	.config_init	= bcm54xx_config_init,
>   	.config_aneg	= genphy_config_aneg,
>   	.read_status	= genphy_read_status,
> -	.ack_interrupt	= bcm54xx_ack_interrupt,
> -	.config_intr	= bcm54xx_config_intr,
> +	.ack_interrupt	= bcm_phy_ack_intr,
> +	.config_intr	= bcm_phy_config_intr,
>   	.driver		= { .owner = THIS_MODULE },
>   }, {
>   	.phy_id		= PHY_ID_BCM57780,
> @@ -636,8 +575,8 @@ static struct phy_driver broadcom_drivers[] = {
>   	.config_init	= bcm54xx_config_init,
>   	.config_aneg	= genphy_config_aneg,
>   	.read_status	= genphy_read_status,
> -	.ack_interrupt	= bcm54xx_ack_interrupt,
> -	.config_intr	= bcm54xx_config_intr,
> +	.ack_interrupt	= bcm_phy_ack_intr,
> +	.config_intr	= bcm_phy_config_intr,
>   	.driver		= { .owner = THIS_MODULE },
>   }, {
>   	.phy_id		= PHY_ID_BCMAC131,
> diff --git a/include/linux/brcmphy.h b/include/linux/brcmphy.h
> index 697ca77..6a53ab9 100644
> --- a/include/linux/brcmphy.h
> +++ b/include/linux/brcmphy.h
> @@ -138,7 +138,10 @@
>   
>   /* 01010: Auto Power-Down */
>   #define BCM54XX_SHD_APD			0x0a
> +#define  BCM_APD_CLR_MASK		0xFE9F /* clear bits 5, 6 & 8 */
>   #define  BCM54XX_SHD_APD_EN		0x0020
> +#define  BCM_NO_ANEG_APD_EN		0x0060 /* bits 5 & 6 */
> +#define  BCM_APD_SINGLELP_EN	0x0100 /* Bit 8 */
>   
>   #define BCM5482_SHD_LEDS1	0x0d	/* 01101: LED Selector 1 */
>   					/* LED3 / ~LINKSPD[2] selector */
> @@ -209,25 +212,6 @@
>   #define MII_BRCM_FET_SHDW_AUXSTAT2	0x1b	/* Auxiliary status 2 */
>   #define MII_BRCM_FET_SHDW_AS2_APDE	0x0020	/* Auto power down enable */
>   
> -/*
> - * Indirect register access functions for the 1000BASE-T/100BASE-TX/10BASE-T
> - * 0x1c shadow registers.
> - */
> -static inline int bcm54xx_shadow_read(struct phy_device *phydev, u16 shadow)
> -{
> -	phy_write(phydev, MII_BCM54XX_SHD, MII_BCM54XX_SHD_VAL(shadow));
> -	return MII_BCM54XX_SHD_DATA(phy_read(phydev, MII_BCM54XX_SHD));
> -}
> -
> -static inline int bcm54xx_shadow_write(struct phy_device *phydev, u16 shadow,
> -				       u16 val)
> -{
> -	return phy_write(phydev, MII_BCM54XX_SHD,
> -			 MII_BCM54XX_SHD_WRITE |
> -			 MII_BCM54XX_SHD_VAL(shadow) |
> -			 MII_BCM54XX_SHD_DATA(val));
> -}
> -
>   #define BRCM_CL45VEN_EEE_CONTROL	0x803d
>   #define LPI_FEATURE_EN			0x8000
>   #define LPI_FEATURE_EN_DIG1000X		0x4000

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Florian Fainelli Oct. 14, 2015, 5:38 p.m. UTC | #2
On 14/10/15 10:33, Robert E Cochran wrote:
> 
> 
> On 10/06/2015 03:25 PM, Arun Parameswaran wrote:
>> This patch adds the Broadcom phy library to consolidate common
>> interfaces shared by Broadcom phy's.
> 
> The BCM54612E is included in the Broadcom Community part portfolio
> (https://community.broadcom.com).  However, I don't see this part
> explicitly supported by your phy library ( e.g., not included in
> broadcom_drivers[] in broadcom.c ).

These are external PHY products which have a different support channel
and engineering teams.

> 
> Can you please comment on whether this part is supported or the extent
> of changes required to establish and support a robust GigE connection
> between RGMII and CU?

This probably deserves a separate thread rather than hijacking an
existing one?

> 
> We're considering this part for a new embedded design, and we need an
> open source driver for it.
> 
> Thanks
> 
> Bob
> 
> 
> 
>>
>> Moved the common interfaces to the 'bcm-phy-lib.c' and updated
>> the Broadcom PHY drivers to use the new APIs.
>>
>> Signed-off-by: Arun Parameswaran <arunp@broadcom.com>
>> ---
>>   drivers/net/phy/Kconfig       |   6 ++
>>   drivers/net/phy/Makefile      |   1 +
>>   drivers/net/phy/bcm-phy-lib.c | 209
>> ++++++++++++++++++++++++++++++++++++++++++
>>   drivers/net/phy/bcm-phy-lib.h |  37 ++++++++
>>   drivers/net/phy/bcm63xx.c     |  38 +-------
>>   drivers/net/phy/bcm7xxx.c     | 127 ++++++-------------------
>>   drivers/net/phy/broadcom.c    | 149 +++++++++---------------------
>>   include/linux/brcmphy.h       |  22 +----
>>   8 files changed, 333 insertions(+), 256 deletions(-)
>>   create mode 100644 drivers/net/phy/bcm-phy-lib.c
>>   create mode 100644 drivers/net/phy/bcm-phy-lib.h
>>
>> diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
>> index b57f6c2..606fdc9 100644
>> --- a/drivers/net/phy/Kconfig
>> +++ b/drivers/net/phy/Kconfig
>> @@ -69,8 +69,12 @@ config SMSC_PHY
>>       ---help---
>>         Currently supports the LAN83C185, LAN8187 and LAN8700 PHYs
>>   +config BCM_NET_PHYLIB
>> +    tristate
>> +
>>   config BROADCOM_PHY
>>       tristate "Drivers for Broadcom PHYs"
>> +    select BCM_NET_PHYLIB
>>       ---help---
>>         Currently supports the BCM5411, BCM5421, BCM5461, BCM54616S,
>> BCM5464,
>>         BCM5481 and BCM5482 PHYs.
>> @@ -78,11 +82,13 @@ config BROADCOM_PHY
>>   config BCM63XX_PHY
>>       tristate "Drivers for Broadcom 63xx SOCs internal PHY"
>>       depends on BCM63XX
>> +    select BCM_NET_PHYLIB
>>       ---help---
>>         Currently supports the 6348 and 6358 PHYs.
>>     config BCM7XXX_PHY
>>       tristate "Drivers for Broadcom 7xxx SOCs internal PHYs"
>> +    select BCM_NET_PHYLIB
>>       ---help---
>>         Currently supports the BCM7366, BCM7439, BCM7445, and
>>         40nm and 65nm generation of BCM7xxx Set Top Box SoCs.
>> diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
>> index f4e6eb9..6932475 100644
>> --- a/drivers/net/phy/Makefile
>> +++ b/drivers/net/phy/Makefile
>> @@ -12,6 +12,7 @@ obj-$(CONFIG_QSEMI_PHY)        += qsemi.o
>>   obj-$(CONFIG_SMSC_PHY)        += smsc.o
>>   obj-$(CONFIG_TERANETICS_PHY)    += teranetics.o
>>   obj-$(CONFIG_VITESSE_PHY)    += vitesse.o
>> +obj-$(CONFIG_BCM_NET_PHYLIB)    += bcm-phy-lib.o
>>   obj-$(CONFIG_BROADCOM_PHY)    += broadcom.o
>>   obj-$(CONFIG_BCM63XX_PHY)    += bcm63xx.o
>>   obj-$(CONFIG_BCM7XXX_PHY)    += bcm7xxx.o
>> diff --git a/drivers/net/phy/bcm-phy-lib.c
>> b/drivers/net/phy/bcm-phy-lib.c
>> new file mode 100644
>> index 0000000..13e161e
>> --- /dev/null
>> +++ b/drivers/net/phy/bcm-phy-lib.c
>> @@ -0,0 +1,209 @@
>> +/*
>> + * Copyright (C) 2015 Broadcom Corporation
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License as
>> + * published by the Free Software Foundation version 2.
>> + *
>> + * This program is distributed "as is" WITHOUT ANY WARRANTY of any
>> + * kind, whether express or implied; without even the implied warranty
>> + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> + * GNU General Public License for more details.
>> + */
>> +
>> +#include "bcm-phy-lib.h"
>> +#include <linux/brcmphy.h>
>> +#include <linux/export.h>
>> +#include <linux/mdio.h>
>> +#include <linux/phy.h>
>> +
>> +#define MII_BCM_CHANNEL_WIDTH     0x2000
>> +#define BCM_CL45VEN_EEE_ADV       0x3c
>> +
>> +int bcm_phy_write_exp(struct phy_device *phydev, u16 reg, u16 val)
>> +{
>> +    int rc;
>> +
>> +    rc = phy_write(phydev, MII_BCM54XX_EXP_SEL, reg);
>> +    if (rc < 0)
>> +        return rc;
>> +
>> +    return phy_write(phydev, MII_BCM54XX_EXP_DATA, val);
>> +}
>> +EXPORT_SYMBOL_GPL(bcm_phy_write_exp);
>> +
>> +int bcm_phy_read_exp(struct phy_device *phydev, u16 reg)
>> +{
>> +    int val;
>> +
>> +    val = phy_write(phydev, MII_BCM54XX_EXP_SEL, reg);
>> +    if (val < 0)
>> +        return val;
>> +
>> +    val = phy_read(phydev, MII_BCM54XX_EXP_DATA);
>> +
>> +    /* Restore default value.  It's O.K. if this write fails. */
>> +    phy_write(phydev, MII_BCM54XX_EXP_SEL, 0);
>> +
>> +    return val;
>> +}
>> +EXPORT_SYMBOL_GPL(bcm_phy_read_exp);
>> +
>> +int bcm_phy_write_misc(struct phy_device *phydev,
>> +               u16 reg, u16 chl, u16 val)
>> +{
>> +    int rc;
>> +    int tmp;
>> +
>> +    rc = phy_write(phydev, MII_BCM54XX_AUX_CTL,
>> +               MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
>> +    if (rc < 0)
>> +        return rc;
>> +
>> +    tmp = phy_read(phydev, MII_BCM54XX_AUX_CTL);
>> +    tmp |= MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA;
>> +    rc = phy_write(phydev, MII_BCM54XX_AUX_CTL, tmp);
>> +    if (rc < 0)
>> +        return rc;
>> +
>> +    tmp = (chl * MII_BCM_CHANNEL_WIDTH) | reg;
>> +    rc = bcm_phy_write_exp(phydev, tmp, val);
>> +
>> +    return rc;
>> +}
>> +EXPORT_SYMBOL_GPL(bcm_phy_write_misc);
>> +
>> +int bcm_phy_read_misc(struct phy_device *phydev,
>> +              u16 reg, u16 chl)
>> +{
>> +    int rc;
>> +    int tmp;
>> +
>> +    rc = phy_write(phydev, MII_BCM54XX_AUX_CTL,
>> +               MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
>> +    if (rc < 0)
>> +        return rc;
>> +
>> +    tmp = phy_read(phydev, MII_BCM54XX_AUX_CTL);
>> +    tmp |= MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA;
>> +    rc = phy_write(phydev, MII_BCM54XX_AUX_CTL, tmp);
>> +    if (rc < 0)
>> +        return rc;
>> +
>> +    tmp = (chl * MII_BCM_CHANNEL_WIDTH) | reg;
>> +    rc = bcm_phy_read_exp(phydev, tmp);
>> +
>> +    return rc;
>> +}
>> +EXPORT_SYMBOL_GPL(bcm_phy_read_misc);
>> +
>> +int bcm_phy_ack_intr(struct phy_device *phydev)
>> +{
>> +    int reg;
>> +
>> +    /* Clear pending interrupts.  */
>> +    reg = phy_read(phydev, MII_BCM54XX_ISR);
>> +    if (reg < 0)
>> +        return reg;
>> +
>> +    return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(bcm_phy_ack_intr);
>> +
>> +int bcm_phy_config_intr(struct phy_device *phydev)
>> +{
>> +    int reg;
>> +
>> +    reg = phy_read(phydev, MII_BCM54XX_ECR);
>> +    if (reg < 0)
>> +        return reg;
>> +
>> +    if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
>> +        reg &= ~MII_BCM54XX_ECR_IM;
>> +    else
>> +        reg |= MII_BCM54XX_ECR_IM;
>> +
>> +    return phy_write(phydev, MII_BCM54XX_ECR, reg);
>> +}
>> +EXPORT_SYMBOL_GPL(bcm_phy_config_intr);
>> +
>> +int bcm_phy_read_shadow(struct phy_device *phydev, u16 shadow)
>> +{
>> +    phy_write(phydev, MII_BCM54XX_SHD, MII_BCM54XX_SHD_VAL(shadow));
>> +    return MII_BCM54XX_SHD_DATA(phy_read(phydev, MII_BCM54XX_SHD));
>> +}
>> +EXPORT_SYMBOL_GPL(bcm_phy_read_shadow);
>> +
>> +int bcm_phy_write_shadow(struct phy_device *phydev, u16 shadow,
>> +             u16 val)
>> +{
>> +    return phy_write(phydev, MII_BCM54XX_SHD,
>> +             MII_BCM54XX_SHD_WRITE |
>> +             MII_BCM54XX_SHD_VAL(shadow) |
>> +             MII_BCM54XX_SHD_DATA(val));
>> +}
>> +EXPORT_SYMBOL_GPL(bcm_phy_write_shadow);
>> +
>> +int bcm_phy_enable_apd(struct phy_device *phydev, bool dll_pwr_down)
>> +{
>> +    int val;
>> +
>> +    if (dll_pwr_down) {
>> +        val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR3);
>> +        if (val < 0)
>> +            return val;
>> +
>> +        val |= BCM54XX_SHD_SCR3_DLLAPD_DIS;
>> +        bcm_phy_write_shadow(phydev, BCM54XX_SHD_SCR3, val);
>> +    }
>> +
>> +    val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_APD);
>> +    if (val < 0)
>> +        return val;
>> +
>> +    /* Clear APD bits */
>> +    val &= BCM_APD_CLR_MASK;
>> +
>> +    if (phydev->autoneg == AUTONEG_ENABLE)
>> +        val |= BCM54XX_SHD_APD_EN;
>> +    else
>> +        val |= BCM_NO_ANEG_APD_EN;
>> +
>> +    /* Enable energy detect single link pulse for easy wakeup */
>> +    val |= BCM_APD_SINGLELP_EN;
>> +
>> +    /* Enable Auto Power-Down (APD) for the PHY */
>> +    return bcm_phy_write_shadow(phydev, BCM54XX_SHD_APD, val);
>> +}
>> +EXPORT_SYMBOL_GPL(bcm_phy_enable_apd);
>> +
>> +int bcm_phy_enable_eee(struct phy_device *phydev)
>> +{
>> +    int val;
>> +
>> +    /* Enable EEE at PHY level */
>> +    val = phy_read_mmd_indirect(phydev, BRCM_CL45VEN_EEE_CONTROL,
>> +                    MDIO_MMD_AN, phydev->addr);
>> +    if (val < 0)
>> +        return val;
>> +
>> +    val |= LPI_FEATURE_EN | LPI_FEATURE_EN_DIG1000X;
>> +
>> +    phy_write_mmd_indirect(phydev, BRCM_CL45VEN_EEE_CONTROL,
>> +                   MDIO_MMD_AN,  phydev->addr, (u32)val);
>> +
>> +    /* Advertise EEE */
>> +    val = phy_read_mmd_indirect(phydev, BCM_CL45VEN_EEE_ADV,
>> +                    MDIO_MMD_AN, phydev->addr);
>> +    if (val < 0)
>> +        return val;
>> +
>> +    val |= (MDIO_AN_EEE_ADV_100TX | MDIO_AN_EEE_ADV_1000T);
>> +
>> +    phy_write_mmd_indirect(phydev, BCM_CL45VEN_EEE_ADV,
>> +                   MDIO_MMD_AN,  phydev->addr, (u32)val);
>> +
>> +    return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(bcm_phy_enable_eee);
>> +
>> diff --git a/drivers/net/phy/bcm-phy-lib.h
>> b/drivers/net/phy/bcm-phy-lib.h
>> new file mode 100644
>> index 0000000..b2091c8
>> --- /dev/null
>> +++ b/drivers/net/phy/bcm-phy-lib.h
>> @@ -0,0 +1,37 @@
>> +/*
>> + * Copyright (C) 2015 Broadcom Corporation
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License as
>> + * published by the Free Software Foundation version 2.
>> + *
>> + * This program is distributed "as is" WITHOUT ANY WARRANTY of any
>> + * kind, whether express or implied; without even the implied warranty
>> + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> + * GNU General Public License for more details.
>> + */
>> +
>> +#ifndef _LINUX_BCM_PHY_LIB_H
>> +#define _LINUX_BCM_PHY_LIB_H
>> +
>> +#include <linux/phy.h>
>> +
>> +int bcm_phy_write_exp(struct phy_device *phydev, u16 reg, u16 val);
>> +int bcm_phy_read_exp(struct phy_device *phydev, u16 reg);
>> +
>> +int bcm_phy_write_misc(struct phy_device *phydev,
>> +               u16 reg, u16 chl, u16 value);
>> +int bcm_phy_read_misc(struct phy_device *phydev,
>> +              u16 reg, u16 chl);
>> +
>> +int bcm_phy_write_shadow(struct phy_device *phydev, u16 shadow,
>> +             u16 val);
>> +int bcm_phy_read_shadow(struct phy_device *phydev, u16 shadow);
>> +
>> +int bcm_phy_ack_intr(struct phy_device *phydev);
>> +int bcm_phy_config_intr(struct phy_device *phydev);
>> +
>> +int bcm_phy_enable_apd(struct phy_device *phydev, bool dll_pwr_down);
>> +
>> +int bcm_phy_enable_eee(struct phy_device *phydev);
>> +#endif /* _LINUX_BCM_PHY_LIB_H */
>> diff --git a/drivers/net/phy/bcm63xx.c b/drivers/net/phy/bcm63xx.c
>> index 830ec31..86b2805 100644
>> --- a/drivers/net/phy/bcm63xx.c
>> +++ b/drivers/net/phy/bcm63xx.c
>> @@ -6,6 +6,7 @@
>>    *    as published by the Free Software Foundation; either version
>>    *    2 of the License, or (at your option) any later version.
>>    */
>> +#include "bcm-phy-lib.h"
>>   #include <linux/module.h>
>>   #include <linux/phy.h>
>>   @@ -42,35 +43,6 @@ static int bcm63xx_config_init(struct phy_device
>> *phydev)
>>       return phy_write(phydev, MII_BCM63XX_IR, reg);
>>   }
>>   -static int bcm63xx_ack_interrupt(struct phy_device *phydev)
>> -{
>> -    int reg;
>> -
>> -    /* Clear pending interrupts.  */
>> -    reg = phy_read(phydev, MII_BCM63XX_IR);
>> -    if (reg < 0)
>> -        return reg;
>> -
>> -    return 0;
>> -}
>> -
>> -static int bcm63xx_config_intr(struct phy_device *phydev)
>> -{
>> -    int reg, err;
>> -
>> -    reg = phy_read(phydev, MII_BCM63XX_IR);
>> -    if (reg < 0)
>> -        return reg;
>> -
>> -    if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
>> -        reg &= ~MII_BCM63XX_IR_GMASK;
>> -    else
>> -        reg |= MII_BCM63XX_IR_GMASK;
>> -
>> -    err = phy_write(phydev, MII_BCM63XX_IR, reg);
>> -    return err;
>> -}
>> -
>>   static struct phy_driver bcm63xx_driver[] = {
>>   {
>>       .phy_id        = 0x00406000,
>> @@ -82,8 +54,8 @@ static struct phy_driver bcm63xx_driver[] = {
>>       .config_init    = bcm63xx_config_init,
>>       .config_aneg    = genphy_config_aneg,
>>       .read_status    = genphy_read_status,
>> -    .ack_interrupt    = bcm63xx_ack_interrupt,
>> -    .config_intr    = bcm63xx_config_intr,
>> +    .ack_interrupt    = bcm_phy_ack_intr,
>> +    .config_intr    = bcm_phy_config_intr,
>>       .driver        = { .owner = THIS_MODULE },
>>   }, {
>>       /* same phy as above, with just a different OUI */
>> @@ -95,8 +67,8 @@ static struct phy_driver bcm63xx_driver[] = {
>>       .config_init    = bcm63xx_config_init,
>>       .config_aneg    = genphy_config_aneg,
>>       .read_status    = genphy_read_status,
>> -    .ack_interrupt    = bcm63xx_ack_interrupt,
>> -    .config_intr    = bcm63xx_config_intr,
>> +    .ack_interrupt    = bcm_phy_ack_intr,
>> +    .config_intr    = bcm_phy_config_intr,
>>       .driver        = { .owner = THIS_MODULE },
>>   } };
>>   diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c
>> index 6b701b3..efa31a6 100644
>> --- a/drivers/net/phy/bcm7xxx.c
>> +++ b/drivers/net/phy/bcm7xxx.c
>> @@ -12,12 +12,12 @@
>>   #include <linux/module.h>
>>   #include <linux/phy.h>
>>   #include <linux/delay.h>
>> +#include "bcm-phy-lib.h"
>>   #include <linux/bitops.h>
>>   #include <linux/brcmphy.h>
>>   #include <linux/mdio.h>
>>     /* Broadcom BCM7xxx internal PHY registers */
>> -#define MII_BCM7XXX_CHANNEL_WIDTH    0x2000
>>     /* 40nm only register definitions */
>>   #define MII_BCM7XXX_100TX_AUX_CTL    0x10
>> @@ -48,37 +48,13 @@
>>     #define CORE_EXPB0            0xb0
>>   -static void phy_write_exp(struct phy_device *phydev,
>> -                    u16 reg, u16 value)
>> -{
>> -    phy_write(phydev, MII_BCM54XX_EXP_SEL, MII_BCM54XX_EXP_SEL_ER |
>> reg);
>> -    phy_write(phydev, MII_BCM54XX_EXP_DATA, value);
>> -}
>> -
>> -static void phy_write_misc(struct phy_device *phydev,
>> -                    u16 reg, u16 chl, u16 value)
>> -{
>> -    int tmp;
>> -
>> -    phy_write(phydev, MII_BCM54XX_AUX_CTL,
>> MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
>> -
>> -    tmp = phy_read(phydev, MII_BCM54XX_AUX_CTL);
>> -    tmp |= MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA;
>> -    phy_write(phydev, MII_BCM54XX_AUX_CTL, tmp);
>> -
>> -    tmp = (chl * MII_BCM7XXX_CHANNEL_WIDTH) | reg;
>> -    phy_write(phydev, MII_BCM54XX_EXP_SEL, tmp);
>> -
>> -    phy_write(phydev, MII_BCM54XX_EXP_DATA, value);
>> -}
>> -
>>   static void r_rc_cal_reset(struct phy_device *phydev)
>>   {
>>       /* Reset R_CAL/RC_CAL Engine */
>> -    phy_write_exp(phydev, 0x00b0, 0x0010);
>> +    bcm_phy_write_exp(phydev, 0x00b0, 0x0010);
>>         /* Disable Reset R_AL/RC_CAL Engine */
>> -    phy_write_exp(phydev, 0x00b0, 0x0000);
>> +    bcm_phy_write_exp(phydev, 0x00b0, 0x0000);
>>   }
>>     static int bcm7xxx_28nm_b0_afe_config_init(struct phy_device *phydev)
>> @@ -86,18 +62,18 @@ static int bcm7xxx_28nm_b0_afe_config_init(struct
>> phy_device *phydev)
>>       /* Increase VCO range to prevent unlocking problem of PLL at low
>>        * temp
>>        */
>> -    phy_write_misc(phydev, PLL_PLLCTRL_1, 0x0048);
>> +    bcm_phy_write_misc(phydev, PLL_PLLCTRL_1, 0x0048);
>>         /* Change Ki to 011 */
>> -    phy_write_misc(phydev, PLL_PLLCTRL_2, 0x021b);
>> +    bcm_phy_write_misc(phydev, PLL_PLLCTRL_2, 0x021b);
>>         /* Disable loading of TVCO buffer to bandgap, set bandgap trim
>>        * to 111
>>        */
>> -    phy_write_misc(phydev, PLL_PLLCTRL_4, 0x0e20);
>> +    bcm_phy_write_misc(phydev, PLL_PLLCTRL_4, 0x0e20);
>>         /* Adjust bias current trim by -3 */
>> -    phy_write_misc(phydev, DSP_TAP10, 0x690b);
>> +    bcm_phy_write_misc(phydev, DSP_TAP10, 0x690b);
>>         /* Switch to CORE_BASE1E */
>>       phy_write(phydev, MII_BCM7XXX_CORE_BASE1E, 0xd);
>> @@ -105,19 +81,19 @@ static int bcm7xxx_28nm_b0_afe_config_init(struct
>> phy_device *phydev)
>>       r_rc_cal_reset(phydev);
>>         /* write AFE_RXCONFIG_0 */
>> -    phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb19);
>> +    bcm_phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb19);
>>         /* write AFE_RXCONFIG_1 */
>> -    phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9a3f);
>> +    bcm_phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9a3f);
>>         /* write AFE_RX_LP_COUNTER */
>> -    phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0);
>> +    bcm_phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0);
>>         /* write AFE_HPF_TRIM_OTHERS */
>> -    phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x000b);
>> +    bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x000b);
>>         /* write AFTE_TX_CONFIG */
>> -    phy_write_misc(phydev, AFE_TX_CONFIG, 0x0800);
>> +    bcm_phy_write_misc(phydev, AFE_TX_CONFIG, 0x0800);
>>         return 0;
>>   }
>> @@ -125,36 +101,36 @@ static int
>> bcm7xxx_28nm_b0_afe_config_init(struct phy_device *phydev)
>>   static int bcm7xxx_28nm_d0_afe_config_init(struct phy_device *phydev)
>>   {
>>       /* AFE_RXCONFIG_0 */
>> -    phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb15);
>> +    bcm_phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb15);
>>         /* AFE_RXCONFIG_1 */
>> -    phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9b2f);
>> +    bcm_phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9b2f);
>>         /* AFE_RXCONFIG_2, set rCal offset for HT=0 code and LT=-2
>> code */
>> -    phy_write_misc(phydev, AFE_RXCONFIG_2, 0x2003);
>> +    bcm_phy_write_misc(phydev, AFE_RXCONFIG_2, 0x2003);
>>         /* AFE_RX_LP_COUNTER, set RX bandwidth to maximum */
>> -    phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0);
>> +    bcm_phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0);
>>         /* AFE_TX_CONFIG, set 100BT Cfeed=011 to improve rise/fall
>> time */
>> -    phy_write_misc(phydev, AFE_TX_CONFIG, 0x431);
>> +    bcm_phy_write_misc(phydev, AFE_TX_CONFIG, 0x431);
>>         /* AFE_VDCA_ICTRL_0, set Iq=1101 instead of 0111 for AB
>> symmetry */
>> -    phy_write_misc(phydev, AFE_VDCA_ICTRL_0, 0xa7da);
>> +    bcm_phy_write_misc(phydev, AFE_VDCA_ICTRL_0, 0xa7da);
>>         /* AFE_VDAC_OTHERS_0, set 1000BT Cidac=010 for all ports */
>> -    phy_write_misc(phydev, AFE_VDAC_OTHERS_0, 0xa020);
>> +    bcm_phy_write_misc(phydev, AFE_VDAC_OTHERS_0, 0xa020);
>>         /* AFE_HPF_TRIM_OTHERS, set 100Tx/10BT to -4.5% swing and set
>> rCal
>>        * offset for HT=0 code
>>        */
>> -    phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x00e3);
>> +    bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x00e3);
>>         /* CORE_BASE1E, force trim to overwrite and set I_ext trim to
>> 0000 */
>>       phy_write(phydev, MII_BCM7XXX_CORE_BASE1E, 0x0010);
>>         /* DSP_TAP10, adjust bias current trim (+0% swing, +0 tick) */
>> -    phy_write_misc(phydev, DSP_TAP10, 0x011b);
>> +    bcm_phy_write_misc(phydev, DSP_TAP10, 0x011b);
>>         /* Reset R_CAL/RC_CAL engine */
>>       r_rc_cal_reset(phydev);
>> @@ -165,24 +141,24 @@ static int
>> bcm7xxx_28nm_d0_afe_config_init(struct phy_device *phydev)
>>   static int bcm7xxx_28nm_e0_plus_afe_config_init(struct phy_device
>> *phydev)
>>   {
>>       /* AFE_RXCONFIG_1, provide more margin for INL/DNL measurement */
>> -    phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9b2f);
>> +    bcm_phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9b2f);
>>         /* AFE_TX_CONFIG, set 100BT Cfeed=011 to improve rise/fall
>> time */
>> -    phy_write_misc(phydev, AFE_TX_CONFIG, 0x431);
>> +    bcm_phy_write_misc(phydev, AFE_TX_CONFIG, 0x431);
>>         /* AFE_VDCA_ICTRL_0, set Iq=1101 instead of 0111 for AB
>> symmetry */
>> -    phy_write_misc(phydev, AFE_VDCA_ICTRL_0, 0xa7da);
>> +    bcm_phy_write_misc(phydev, AFE_VDCA_ICTRL_0, 0xa7da);
>>         /* AFE_HPF_TRIM_OTHERS, set 100Tx/10BT to -4.5% swing and set
>> rCal
>>        * offset for HT=0 code
>>        */
>> -    phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x00e3);
>> +    bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x00e3);
>>         /* CORE_BASE1E, force trim to overwrite and set I_ext trim to
>> 0000 */
>>       phy_write(phydev, MII_BCM7XXX_CORE_BASE1E, 0x0010);
>>         /* DSP_TAP10, adjust bias current trim (+0% swing, +0 tick) */
>> -    phy_write_misc(phydev, DSP_TAP10, 0x011b);
>> +    bcm_phy_write_misc(phydev, DSP_TAP10, 0x011b);
>>         /* Reset R_CAL/RC_CAL engine */
>>       r_rc_cal_reset(phydev);
>> @@ -190,53 +166,6 @@ static int
>> bcm7xxx_28nm_e0_plus_afe_config_init(struct phy_device *phydev)
>>       return 0;
>>   }
>>   -static int bcm7xxx_apd_enable(struct phy_device *phydev)
>> -{
>> -    int val;
>> -
>> -    /* Enable powering down of the DLL during auto-power down */
>> -    val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_SCR3);
>> -    if (val < 0)
>> -        return val;
>> -
>> -    val |= BCM54XX_SHD_SCR3_DLLAPD_DIS;
>> -    bcm54xx_shadow_write(phydev, BCM54XX_SHD_SCR3, val);
>> -
>> -    /* Enable auto-power down */
>> -    val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_APD);
>> -    if (val < 0)
>> -        return val;
>> -
>> -    val |= BCM54XX_SHD_APD_EN;
>> -    return bcm54xx_shadow_write(phydev, BCM54XX_SHD_APD, val);
>> -}
>> -
>> -static int bcm7xxx_eee_enable(struct phy_device *phydev)
>> -{
>> -    int val;
>> -
>> -    val = phy_read_mmd_indirect(phydev, BRCM_CL45VEN_EEE_CONTROL,
>> -                    MDIO_MMD_AN, phydev->addr);
>> -    if (val < 0)
>> -        return val;
>> -
>> -    /* Enable general EEE feature at the PHY level */
>> -    val |= LPI_FEATURE_EN | LPI_FEATURE_EN_DIG1000X;
>> -
>> -    phy_write_mmd_indirect(phydev, BRCM_CL45VEN_EEE_CONTROL,
>> -                   MDIO_MMD_AN, phydev->addr, val);
>> -
>> -    /* Advertise supported modes */
>> -    val = phy_read_mmd_indirect(phydev, MDIO_AN_EEE_ADV,
>> -                    MDIO_MMD_AN, phydev->addr);
>> -
>> -    val |= (MDIO_AN_EEE_ADV_100TX | MDIO_AN_EEE_ADV_1000T);
>> -    phy_write_mmd_indirect(phydev, MDIO_AN_EEE_ADV,
>> -                   MDIO_MMD_AN, phydev->addr, val);
>> -
>> -    return 0;
>> -}
>> -
>>   static int bcm7xxx_28nm_config_init(struct phy_device *phydev)
>>   {
>>       u8 rev = PHY_BRCM_7XXX_REV(phydev->dev_flags);
>> @@ -273,11 +202,11 @@ static int bcm7xxx_28nm_config_init(struct
>> phy_device *phydev)
>>       if (ret)
>>           return ret;
>>   -    ret = bcm7xxx_eee_enable(phydev);
>> +    ret = bcm_phy_enable_eee(phydev);
>>       if (ret)
>>           return ret;
>>   -    return bcm7xxx_apd_enable(phydev);
>> +    return bcm_phy_enable_apd(phydev, true);
>>   }
>>     static int bcm7xxx_28nm_resume(struct phy_device *phydev)
>> diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
>> index 9c71295..07a6119 100644
>> --- a/drivers/net/phy/broadcom.c
>> +++ b/drivers/net/phy/broadcom.c
>> @@ -14,6 +14,7 @@
>>    *    2 of the License, or (at your option) any later version.
>>    */
>>   +#include "bcm-phy-lib.h"
>>   #include <linux/module.h>
>>   #include <linux/phy.h>
>>   #include <linux/brcmphy.h>
>> @@ -29,39 +30,6 @@ MODULE_DESCRIPTION("Broadcom PHY driver");
>>   MODULE_AUTHOR("Maciej W. Rozycki");
>>   MODULE_LICENSE("GPL");
>>   -/* Indirect register access functions for the Expansion Registers */
>> -static int bcm54xx_exp_read(struct phy_device *phydev, u16 regnum)
>> -{
>> -    int val;
>> -
>> -    val = phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum);
>> -    if (val < 0)
>> -        return val;
>> -
>> -    val = phy_read(phydev, MII_BCM54XX_EXP_DATA);
>> -
>> -    /* Restore default value.  It's O.K. if this write fails. */
>> -    phy_write(phydev, MII_BCM54XX_EXP_SEL, 0);
>> -
>> -    return val;
>> -}
>> -
>> -static int bcm54xx_exp_write(struct phy_device *phydev, u16 regnum,
>> u16 val)
>> -{
>> -    int ret;
>> -
>> -    ret = phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum);
>> -    if (ret < 0)
>> -        return ret;
>> -
>> -    ret = phy_write(phydev, MII_BCM54XX_EXP_DATA, val);
>> -
>> -    /* Restore default value.  It's O.K. if this write fails. */
>> -    phy_write(phydev, MII_BCM54XX_EXP_SEL, 0);
>> -
>> -    return ret;
>> -}
>> -
>>   static int bcm54xx_auxctl_write(struct phy_device *phydev, u16
>> regnum, u16 val)
>>   {
>>       return phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum | val);
>> @@ -72,28 +40,28 @@ static int bcm50610_a0_workaround(struct
>> phy_device *phydev)
>>   {
>>       int err;
>>   -    err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH0,
>> +    err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_AADJ1CH0,
>>                   MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN |
>>                   MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF);
>>       if (err < 0)
>>           return err;
>>   -    err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH3,
>> -                    MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ);
>> +    err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_AADJ1CH3,
>> +                MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ);
>>       if (err < 0)
>>           return err;
>>   -    err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP75,
>> +    err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP75,
>>                   MII_BCM54XX_EXP_EXP75_VDACCTRL);
>>       if (err < 0)
>>           return err;
>>   -    err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP96,
>> +    err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP96,
>>                   MII_BCM54XX_EXP_EXP96_MYST);
>>       if (err < 0)
>>           return err;
>>   -    err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP97,
>> +    err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP97,
>>                   MII_BCM54XX_EXP_EXP97_MYST);
>>         return err;
>> @@ -114,7 +82,7 @@ static int bcm54xx_phydsp_config(struct phy_device
>> *phydev)
>>       if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
>>           BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) {
>>           /* Clear bit 9 to fix a phy interop issue. */
>> -        err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP08,
>> +        err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP08,
>>                       MII_BCM54XX_EXP_EXP08_RJCT_2MHZ);
>>           if (err < 0)
>>               goto error;
>> @@ -129,12 +97,12 @@ static int bcm54xx_phydsp_config(struct
>> phy_device *phydev)
>>       if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM57780) {
>>           int val;
>>   -        val = bcm54xx_exp_read(phydev, MII_BCM54XX_EXP_EXP75);
>> +        val = bcm_phy_read_exp(phydev, MII_BCM54XX_EXP_EXP75);
>>           if (val < 0)
>>               goto error;
>>             val |= MII_BCM54XX_EXP_EXP75_CM_OSC;
>> -        err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP75, val);
>> +        err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP75, val);
>>       }
>>     error:
>> @@ -159,7 +127,7 @@ static void bcm54xx_adjust_rxrefclk(struct
>> phy_device *phydev)
>>           BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610M)
>>           return;
>>   -    val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_SCR3);
>> +    val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR3);
>>       if (val < 0)
>>           return;
>>   @@ -190,9 +158,9 @@ static void bcm54xx_adjust_rxrefclk(struct
>> phy_device *phydev)
>>           val |= BCM54XX_SHD_SCR3_TRDDAPD;
>>         if (orig != val)
>> -        bcm54xx_shadow_write(phydev, BCM54XX_SHD_SCR3, val);
>> +        bcm_phy_write_shadow(phydev, BCM54XX_SHD_SCR3, val);
>>   -    val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_APD);
>> +    val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_APD);
>>       if (val < 0)
>>           return;
>>   @@ -204,7 +172,7 @@ static void bcm54xx_adjust_rxrefclk(struct
>> phy_device *phydev)
>>           val &= ~BCM54XX_SHD_APD_EN;
>>         if (orig != val)
>> -        bcm54xx_shadow_write(phydev, BCM54XX_SHD_APD, val);
>> +        bcm_phy_write_shadow(phydev, BCM54XX_SHD_APD, val);
>>   }
>>     static int bcm54xx_config_init(struct phy_device *phydev)
>> @@ -232,7 +200,7 @@ static int bcm54xx_config_init(struct phy_device
>> *phydev)
>>       if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
>>            BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) &&
>>           (phydev->dev_flags & PHY_BRCM_CLEAR_RGMII_MODE))
>> -        bcm54xx_shadow_write(phydev, BCM54XX_SHD_RGMII_MODE, 0);
>> +        bcm_phy_write_shadow(phydev, BCM54XX_SHD_RGMII_MODE, 0);
>>         if ((phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) ||
>>           (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY) ||
>> @@ -254,8 +222,8 @@ static int bcm5482_config_init(struct phy_device
>> *phydev)
>>           /*
>>            * Enable secondary SerDes and its use as an LED source
>>            */
>> -        reg = bcm54xx_shadow_read(phydev, BCM5482_SHD_SSD);
>> -        bcm54xx_shadow_write(phydev, BCM5482_SHD_SSD,
>> +        reg = bcm_phy_read_shadow(phydev, BCM5482_SHD_SSD);
>> +        bcm_phy_write_shadow(phydev, BCM5482_SHD_SSD,
>>                        reg |
>>                        BCM5482_SHD_SSD_LEDM |
>>                        BCM5482_SHD_SSD_EN);
>> @@ -264,10 +232,10 @@ static int bcm5482_config_init(struct phy_device
>> *phydev)
>>            * Enable SGMII slave mode and auto-detection
>>            */
>>           reg = BCM5482_SSD_SGMII_SLAVE | MII_BCM54XX_EXP_SEL_SSD;
>> -        err = bcm54xx_exp_read(phydev, reg);
>> +        err = bcm_phy_read_exp(phydev, reg);
>>           if (err < 0)
>>               return err;
>> -        err = bcm54xx_exp_write(phydev, reg, err |
>> +        err = bcm_phy_write_exp(phydev, reg, err |
>>                       BCM5482_SSD_SGMII_SLAVE_EN |
>>                       BCM5482_SSD_SGMII_SLAVE_AD);
>>           if (err < 0)
>> @@ -277,10 +245,10 @@ static int bcm5482_config_init(struct phy_device
>> *phydev)
>>            * Disable secondary SerDes powerdown
>>            */
>>           reg = BCM5482_SSD_1000BX_CTL | MII_BCM54XX_EXP_SEL_SSD;
>> -        err = bcm54xx_exp_read(phydev, reg);
>> +        err = bcm_phy_read_exp(phydev, reg);
>>           if (err < 0)
>>               return err;
>> -        err = bcm54xx_exp_write(phydev, reg,
>> +        err = bcm_phy_write_exp(phydev, reg,
>>                       err & ~BCM5482_SSD_1000BX_CTL_PWRDOWN);
>>           if (err < 0)
>>               return err;
>> @@ -288,15 +256,15 @@ static int bcm5482_config_init(struct phy_device
>> *phydev)
>>           /*
>>            * Select 1000BASE-X register set (primary SerDes)
>>            */
>> -        reg = bcm54xx_shadow_read(phydev, BCM5482_SHD_MODE);
>> -        bcm54xx_shadow_write(phydev, BCM5482_SHD_MODE,
>> +        reg = bcm_phy_read_shadow(phydev, BCM5482_SHD_MODE);
>> +        bcm_phy_write_shadow(phydev, BCM5482_SHD_MODE,
>>                        reg | BCM5482_SHD_MODE_1000BX);
>>             /*
>>            * LED1=ACTIVITYLED, LED3=LINKSPD[2]
>>            * (Use LED1 as secondary SerDes ACTIVITY LED)
>>            */
>> -        bcm54xx_shadow_write(phydev, BCM5482_SHD_LEDS1,
>> +        bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1,
>>               BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_ACTIVITYLED) |
>>               BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_LINKSPD2));
>>   @@ -334,35 +302,6 @@ static int bcm5482_read_status(struct
>> phy_device *phydev)
>>       return err;
>>   }
>>   -static int bcm54xx_ack_interrupt(struct phy_device *phydev)
>> -{
>> -    int reg;
>> -
>> -    /* Clear pending interrupts.  */
>> -    reg = phy_read(phydev, MII_BCM54XX_ISR);
>> -    if (reg < 0)
>> -        return reg;
>> -
>> -    return 0;
>> -}
>> -
>> -static int bcm54xx_config_intr(struct phy_device *phydev)
>> -{
>> -    int reg, err;
>> -
>> -    reg = phy_read(phydev, MII_BCM54XX_ECR);
>> -    if (reg < 0)
>> -        return reg;
>> -
>> -    if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
>> -        reg &= ~MII_BCM54XX_ECR_IM;
>> -    else
>> -        reg |= MII_BCM54XX_ECR_IM;
>> -
>> -    err = phy_write(phydev, MII_BCM54XX_ECR, reg);
>> -    return err;
>> -}
>> -
>>   static int bcm5481_config_aneg(struct phy_device *phydev)
>>   {
>>       int ret;
>> @@ -519,8 +458,8 @@ static struct phy_driver broadcom_drivers[] = {
>>       .config_init    = bcm54xx_config_init,
>>       .config_aneg    = genphy_config_aneg,
>>       .read_status    = genphy_read_status,
>> -    .ack_interrupt    = bcm54xx_ack_interrupt,
>> -    .config_intr    = bcm54xx_config_intr,
>> +    .ack_interrupt    = bcm_phy_ack_intr,
>> +    .config_intr    = bcm_phy_config_intr,
>>       .driver        = { .owner = THIS_MODULE },
>>   }, {
>>       .phy_id        = PHY_ID_BCM5421,
>> @@ -532,8 +471,8 @@ static struct phy_driver broadcom_drivers[] = {
>>       .config_init    = bcm54xx_config_init,
>>       .config_aneg    = genphy_config_aneg,
>>       .read_status    = genphy_read_status,
>> -    .ack_interrupt    = bcm54xx_ack_interrupt,
>> -    .config_intr    = bcm54xx_config_intr,
>> +    .ack_interrupt    = bcm_phy_ack_intr,
>> +    .config_intr    = bcm_phy_config_intr,
>>       .driver        = { .owner = THIS_MODULE },
>>   }, {
>>       .phy_id        = PHY_ID_BCM5461,
>> @@ -545,8 +484,8 @@ static struct phy_driver broadcom_drivers[] = {
>>       .config_init    = bcm54xx_config_init,
>>       .config_aneg    = genphy_config_aneg,
>>       .read_status    = genphy_read_status,
>> -    .ack_interrupt    = bcm54xx_ack_interrupt,
>> -    .config_intr    = bcm54xx_config_intr,
>> +    .ack_interrupt    = bcm_phy_ack_intr,
>> +    .config_intr    = bcm_phy_config_intr,
>>       .driver        = { .owner = THIS_MODULE },
>>   }, {
>>       .phy_id        = PHY_ID_BCM54616S,
>> @@ -558,8 +497,8 @@ static struct phy_driver broadcom_drivers[] = {
>>       .config_init    = bcm54xx_config_init,
>>       .config_aneg    = genphy_config_aneg,
>>       .read_status    = genphy_read_status,
>> -    .ack_interrupt    = bcm54xx_ack_interrupt,
>> -    .config_intr    = bcm54xx_config_intr,
>> +    .ack_interrupt    = bcm_phy_ack_intr,
>> +    .config_intr    = bcm_phy_config_intr,
>>       .driver        = { .owner = THIS_MODULE },
>>   }, {
>>       .phy_id        = PHY_ID_BCM5464,
>> @@ -571,8 +510,8 @@ static struct phy_driver broadcom_drivers[] = {
>>       .config_init    = bcm54xx_config_init,
>>       .config_aneg    = genphy_config_aneg,
>>       .read_status    = genphy_read_status,
>> -    .ack_interrupt    = bcm54xx_ack_interrupt,
>> -    .config_intr    = bcm54xx_config_intr,
>> +    .ack_interrupt    = bcm_phy_ack_intr,
>> +    .config_intr    = bcm_phy_config_intr,
>>       .driver        = { .owner = THIS_MODULE },
>>   }, {
>>       .phy_id        = PHY_ID_BCM5481,
>> @@ -584,8 +523,8 @@ static struct phy_driver broadcom_drivers[] = {
>>       .config_init    = bcm54xx_config_init,
>>       .config_aneg    = bcm5481_config_aneg,
>>       .read_status    = genphy_read_status,
>> -    .ack_interrupt    = bcm54xx_ack_interrupt,
>> -    .config_intr    = bcm54xx_config_intr,
>> +    .ack_interrupt    = bcm_phy_ack_intr,
>> +    .config_intr    = bcm_phy_config_intr,
>>       .driver        = { .owner = THIS_MODULE },
>>   }, {
>>       .phy_id        = PHY_ID_BCM5482,
>> @@ -597,8 +536,8 @@ static struct phy_driver broadcom_drivers[] = {
>>       .config_init    = bcm5482_config_init,
>>       .config_aneg    = genphy_config_aneg,
>>       .read_status    = bcm5482_read_status,
>> -    .ack_interrupt    = bcm54xx_ack_interrupt,
>> -    .config_intr    = bcm54xx_config_intr,
>> +    .ack_interrupt    = bcm_phy_ack_intr,
>> +    .config_intr    = bcm_phy_config_intr,
>>       .driver        = { .owner = THIS_MODULE },
>>   }, {
>>       .phy_id        = PHY_ID_BCM50610,
>> @@ -610,8 +549,8 @@ static struct phy_driver broadcom_drivers[] = {
>>       .config_init    = bcm54xx_config_init,
>>       .config_aneg    = genphy_config_aneg,
>>       .read_status    = genphy_read_status,
>> -    .ack_interrupt    = bcm54xx_ack_interrupt,
>> -    .config_intr    = bcm54xx_config_intr,
>> +    .ack_interrupt    = bcm_phy_ack_intr,
>> +    .config_intr    = bcm_phy_config_intr,
>>       .driver        = { .owner = THIS_MODULE },
>>   }, {
>>       .phy_id        = PHY_ID_BCM50610M,
>> @@ -623,8 +562,8 @@ static struct phy_driver broadcom_drivers[] = {
>>       .config_init    = bcm54xx_config_init,
>>       .config_aneg    = genphy_config_aneg,
>>       .read_status    = genphy_read_status,
>> -    .ack_interrupt    = bcm54xx_ack_interrupt,
>> -    .config_intr    = bcm54xx_config_intr,
>> +    .ack_interrupt    = bcm_phy_ack_intr,
>> +    .config_intr    = bcm_phy_config_intr,
>>       .driver        = { .owner = THIS_MODULE },
>>   }, {
>>       .phy_id        = PHY_ID_BCM57780,
>> @@ -636,8 +575,8 @@ static struct phy_driver broadcom_drivers[] = {
>>       .config_init    = bcm54xx_config_init,
>>       .config_aneg    = genphy_config_aneg,
>>       .read_status    = genphy_read_status,
>> -    .ack_interrupt    = bcm54xx_ack_interrupt,
>> -    .config_intr    = bcm54xx_config_intr,
>> +    .ack_interrupt    = bcm_phy_ack_intr,
>> +    .config_intr    = bcm_phy_config_intr,
>>       .driver        = { .owner = THIS_MODULE },
>>   }, {
>>       .phy_id        = PHY_ID_BCMAC131,
>> diff --git a/include/linux/brcmphy.h b/include/linux/brcmphy.h
>> index 697ca77..6a53ab9 100644
>> --- a/include/linux/brcmphy.h
>> +++ b/include/linux/brcmphy.h
>> @@ -138,7 +138,10 @@
>>     /* 01010: Auto Power-Down */
>>   #define BCM54XX_SHD_APD            0x0a
>> +#define  BCM_APD_CLR_MASK        0xFE9F /* clear bits 5, 6 & 8 */
>>   #define  BCM54XX_SHD_APD_EN        0x0020
>> +#define  BCM_NO_ANEG_APD_EN        0x0060 /* bits 5 & 6 */
>> +#define  BCM_APD_SINGLELP_EN    0x0100 /* Bit 8 */
>>     #define BCM5482_SHD_LEDS1    0x0d    /* 01101: LED Selector 1 */
>>                       /* LED3 / ~LINKSPD[2] selector */
>> @@ -209,25 +212,6 @@
>>   #define MII_BRCM_FET_SHDW_AUXSTAT2    0x1b    /* Auxiliary status 2 */
>>   #define MII_BRCM_FET_SHDW_AS2_APDE    0x0020    /* Auto power down
>> enable */
>>   -/*
>> - * Indirect register access functions for the
>> 1000BASE-T/100BASE-TX/10BASE-T
>> - * 0x1c shadow registers.
>> - */
>> -static inline int bcm54xx_shadow_read(struct phy_device *phydev, u16
>> shadow)
>> -{
>> -    phy_write(phydev, MII_BCM54XX_SHD, MII_BCM54XX_SHD_VAL(shadow));
>> -    return MII_BCM54XX_SHD_DATA(phy_read(phydev, MII_BCM54XX_SHD));
>> -}
>> -
>> -static inline int bcm54xx_shadow_write(struct phy_device *phydev, u16
>> shadow,
>> -                       u16 val)
>> -{
>> -    return phy_write(phydev, MII_BCM54XX_SHD,
>> -             MII_BCM54XX_SHD_WRITE |
>> -             MII_BCM54XX_SHD_VAL(shadow) |
>> -             MII_BCM54XX_SHD_DATA(val));
>> -}
>> -
>>   #define BRCM_CL45VEN_EEE_CONTROL    0x803d
>>   #define LPI_FEATURE_EN            0x8000
>>   #define LPI_FEATURE_EN_DIG1000X        0x4000
>
diff mbox

Patch

diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index b57f6c2..606fdc9 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -69,8 +69,12 @@  config SMSC_PHY
 	---help---
 	  Currently supports the LAN83C185, LAN8187 and LAN8700 PHYs
 
+config BCM_NET_PHYLIB
+	tristate
+
 config BROADCOM_PHY
 	tristate "Drivers for Broadcom PHYs"
+	select BCM_NET_PHYLIB
 	---help---
 	  Currently supports the BCM5411, BCM5421, BCM5461, BCM54616S, BCM5464,
 	  BCM5481 and BCM5482 PHYs.
@@ -78,11 +82,13 @@  config BROADCOM_PHY
 config BCM63XX_PHY
 	tristate "Drivers for Broadcom 63xx SOCs internal PHY"
 	depends on BCM63XX
+	select BCM_NET_PHYLIB
 	---help---
 	  Currently supports the 6348 and 6358 PHYs.
 
 config BCM7XXX_PHY
 	tristate "Drivers for Broadcom 7xxx SOCs internal PHYs"
+	select BCM_NET_PHYLIB
 	---help---
 	  Currently supports the BCM7366, BCM7439, BCM7445, and
 	  40nm and 65nm generation of BCM7xxx Set Top Box SoCs.
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index f4e6eb9..6932475 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -12,6 +12,7 @@  obj-$(CONFIG_QSEMI_PHY)		+= qsemi.o
 obj-$(CONFIG_SMSC_PHY)		+= smsc.o
 obj-$(CONFIG_TERANETICS_PHY)	+= teranetics.o
 obj-$(CONFIG_VITESSE_PHY)	+= vitesse.o
+obj-$(CONFIG_BCM_NET_PHYLIB)	+= bcm-phy-lib.o
 obj-$(CONFIG_BROADCOM_PHY)	+= broadcom.o
 obj-$(CONFIG_BCM63XX_PHY)	+= bcm63xx.o
 obj-$(CONFIG_BCM7XXX_PHY)	+= bcm7xxx.o
diff --git a/drivers/net/phy/bcm-phy-lib.c b/drivers/net/phy/bcm-phy-lib.c
new file mode 100644
index 0000000..13e161e
--- /dev/null
+++ b/drivers/net/phy/bcm-phy-lib.c
@@ -0,0 +1,209 @@ 
+/*
+ * Copyright (C) 2015 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "bcm-phy-lib.h"
+#include <linux/brcmphy.h>
+#include <linux/export.h>
+#include <linux/mdio.h>
+#include <linux/phy.h>
+
+#define MII_BCM_CHANNEL_WIDTH     0x2000
+#define BCM_CL45VEN_EEE_ADV       0x3c
+
+int bcm_phy_write_exp(struct phy_device *phydev, u16 reg, u16 val)
+{
+	int rc;
+
+	rc = phy_write(phydev, MII_BCM54XX_EXP_SEL, reg);
+	if (rc < 0)
+		return rc;
+
+	return phy_write(phydev, MII_BCM54XX_EXP_DATA, val);
+}
+EXPORT_SYMBOL_GPL(bcm_phy_write_exp);
+
+int bcm_phy_read_exp(struct phy_device *phydev, u16 reg)
+{
+	int val;
+
+	val = phy_write(phydev, MII_BCM54XX_EXP_SEL, reg);
+	if (val < 0)
+		return val;
+
+	val = phy_read(phydev, MII_BCM54XX_EXP_DATA);
+
+	/* Restore default value.  It's O.K. if this write fails. */
+	phy_write(phydev, MII_BCM54XX_EXP_SEL, 0);
+
+	return val;
+}
+EXPORT_SYMBOL_GPL(bcm_phy_read_exp);
+
+int bcm_phy_write_misc(struct phy_device *phydev,
+		       u16 reg, u16 chl, u16 val)
+{
+	int rc;
+	int tmp;
+
+	rc = phy_write(phydev, MII_BCM54XX_AUX_CTL,
+		       MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
+	if (rc < 0)
+		return rc;
+
+	tmp = phy_read(phydev, MII_BCM54XX_AUX_CTL);
+	tmp |= MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA;
+	rc = phy_write(phydev, MII_BCM54XX_AUX_CTL, tmp);
+	if (rc < 0)
+		return rc;
+
+	tmp = (chl * MII_BCM_CHANNEL_WIDTH) | reg;
+	rc = bcm_phy_write_exp(phydev, tmp, val);
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(bcm_phy_write_misc);
+
+int bcm_phy_read_misc(struct phy_device *phydev,
+		      u16 reg, u16 chl)
+{
+	int rc;
+	int tmp;
+
+	rc = phy_write(phydev, MII_BCM54XX_AUX_CTL,
+		       MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
+	if (rc < 0)
+		return rc;
+
+	tmp = phy_read(phydev, MII_BCM54XX_AUX_CTL);
+	tmp |= MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA;
+	rc = phy_write(phydev, MII_BCM54XX_AUX_CTL, tmp);
+	if (rc < 0)
+		return rc;
+
+	tmp = (chl * MII_BCM_CHANNEL_WIDTH) | reg;
+	rc = bcm_phy_read_exp(phydev, tmp);
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(bcm_phy_read_misc);
+
+int bcm_phy_ack_intr(struct phy_device *phydev)
+{
+	int reg;
+
+	/* Clear pending interrupts.  */
+	reg = phy_read(phydev, MII_BCM54XX_ISR);
+	if (reg < 0)
+		return reg;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(bcm_phy_ack_intr);
+
+int bcm_phy_config_intr(struct phy_device *phydev)
+{
+	int reg;
+
+	reg = phy_read(phydev, MII_BCM54XX_ECR);
+	if (reg < 0)
+		return reg;
+
+	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+		reg &= ~MII_BCM54XX_ECR_IM;
+	else
+		reg |= MII_BCM54XX_ECR_IM;
+
+	return phy_write(phydev, MII_BCM54XX_ECR, reg);
+}
+EXPORT_SYMBOL_GPL(bcm_phy_config_intr);
+
+int bcm_phy_read_shadow(struct phy_device *phydev, u16 shadow)
+{
+	phy_write(phydev, MII_BCM54XX_SHD, MII_BCM54XX_SHD_VAL(shadow));
+	return MII_BCM54XX_SHD_DATA(phy_read(phydev, MII_BCM54XX_SHD));
+}
+EXPORT_SYMBOL_GPL(bcm_phy_read_shadow);
+
+int bcm_phy_write_shadow(struct phy_device *phydev, u16 shadow,
+			 u16 val)
+{
+	return phy_write(phydev, MII_BCM54XX_SHD,
+			 MII_BCM54XX_SHD_WRITE |
+			 MII_BCM54XX_SHD_VAL(shadow) |
+			 MII_BCM54XX_SHD_DATA(val));
+}
+EXPORT_SYMBOL_GPL(bcm_phy_write_shadow);
+
+int bcm_phy_enable_apd(struct phy_device *phydev, bool dll_pwr_down)
+{
+	int val;
+
+	if (dll_pwr_down) {
+		val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR3);
+		if (val < 0)
+			return val;
+
+		val |= BCM54XX_SHD_SCR3_DLLAPD_DIS;
+		bcm_phy_write_shadow(phydev, BCM54XX_SHD_SCR3, val);
+	}
+
+	val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_APD);
+	if (val < 0)
+		return val;
+
+	/* Clear APD bits */
+	val &= BCM_APD_CLR_MASK;
+
+	if (phydev->autoneg == AUTONEG_ENABLE)
+		val |= BCM54XX_SHD_APD_EN;
+	else
+		val |= BCM_NO_ANEG_APD_EN;
+
+	/* Enable energy detect single link pulse for easy wakeup */
+	val |= BCM_APD_SINGLELP_EN;
+
+	/* Enable Auto Power-Down (APD) for the PHY */
+	return bcm_phy_write_shadow(phydev, BCM54XX_SHD_APD, val);
+}
+EXPORT_SYMBOL_GPL(bcm_phy_enable_apd);
+
+int bcm_phy_enable_eee(struct phy_device *phydev)
+{
+	int val;
+
+	/* Enable EEE at PHY level */
+	val = phy_read_mmd_indirect(phydev, BRCM_CL45VEN_EEE_CONTROL,
+				    MDIO_MMD_AN, phydev->addr);
+	if (val < 0)
+		return val;
+
+	val |= LPI_FEATURE_EN | LPI_FEATURE_EN_DIG1000X;
+
+	phy_write_mmd_indirect(phydev, BRCM_CL45VEN_EEE_CONTROL,
+			       MDIO_MMD_AN,  phydev->addr, (u32)val);
+
+	/* Advertise EEE */
+	val = phy_read_mmd_indirect(phydev, BCM_CL45VEN_EEE_ADV,
+				    MDIO_MMD_AN, phydev->addr);
+	if (val < 0)
+		return val;
+
+	val |= (MDIO_AN_EEE_ADV_100TX | MDIO_AN_EEE_ADV_1000T);
+
+	phy_write_mmd_indirect(phydev, BCM_CL45VEN_EEE_ADV,
+			       MDIO_MMD_AN,  phydev->addr, (u32)val);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(bcm_phy_enable_eee);
+
diff --git a/drivers/net/phy/bcm-phy-lib.h b/drivers/net/phy/bcm-phy-lib.h
new file mode 100644
index 0000000..b2091c8
--- /dev/null
+++ b/drivers/net/phy/bcm-phy-lib.h
@@ -0,0 +1,37 @@ 
+/*
+ * Copyright (C) 2015 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _LINUX_BCM_PHY_LIB_H
+#define _LINUX_BCM_PHY_LIB_H
+
+#include <linux/phy.h>
+
+int bcm_phy_write_exp(struct phy_device *phydev, u16 reg, u16 val);
+int bcm_phy_read_exp(struct phy_device *phydev, u16 reg);
+
+int bcm_phy_write_misc(struct phy_device *phydev,
+		       u16 reg, u16 chl, u16 value);
+int bcm_phy_read_misc(struct phy_device *phydev,
+		      u16 reg, u16 chl);
+
+int bcm_phy_write_shadow(struct phy_device *phydev, u16 shadow,
+			 u16 val);
+int bcm_phy_read_shadow(struct phy_device *phydev, u16 shadow);
+
+int bcm_phy_ack_intr(struct phy_device *phydev);
+int bcm_phy_config_intr(struct phy_device *phydev);
+
+int bcm_phy_enable_apd(struct phy_device *phydev, bool dll_pwr_down);
+
+int bcm_phy_enable_eee(struct phy_device *phydev);
+#endif /* _LINUX_BCM_PHY_LIB_H */
diff --git a/drivers/net/phy/bcm63xx.c b/drivers/net/phy/bcm63xx.c
index 830ec31..86b2805 100644
--- a/drivers/net/phy/bcm63xx.c
+++ b/drivers/net/phy/bcm63xx.c
@@ -6,6 +6,7 @@ 
  *	as published by the Free Software Foundation; either version
  *	2 of the License, or (at your option) any later version.
  */
+#include "bcm-phy-lib.h"
 #include <linux/module.h>
 #include <linux/phy.h>
 
@@ -42,35 +43,6 @@  static int bcm63xx_config_init(struct phy_device *phydev)
 	return phy_write(phydev, MII_BCM63XX_IR, reg);
 }
 
-static int bcm63xx_ack_interrupt(struct phy_device *phydev)
-{
-	int reg;
-
-	/* Clear pending interrupts.  */
-	reg = phy_read(phydev, MII_BCM63XX_IR);
-	if (reg < 0)
-		return reg;
-
-	return 0;
-}
-
-static int bcm63xx_config_intr(struct phy_device *phydev)
-{
-	int reg, err;
-
-	reg = phy_read(phydev, MII_BCM63XX_IR);
-	if (reg < 0)
-		return reg;
-
-	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
-		reg &= ~MII_BCM63XX_IR_GMASK;
-	else
-		reg |= MII_BCM63XX_IR_GMASK;
-
-	err = phy_write(phydev, MII_BCM63XX_IR, reg);
-	return err;
-}
-
 static struct phy_driver bcm63xx_driver[] = {
 {
 	.phy_id		= 0x00406000,
@@ -82,8 +54,8 @@  static struct phy_driver bcm63xx_driver[] = {
 	.config_init	= bcm63xx_config_init,
 	.config_aneg	= genphy_config_aneg,
 	.read_status	= genphy_read_status,
-	.ack_interrupt	= bcm63xx_ack_interrupt,
-	.config_intr	= bcm63xx_config_intr,
+	.ack_interrupt	= bcm_phy_ack_intr,
+	.config_intr	= bcm_phy_config_intr,
 	.driver		= { .owner = THIS_MODULE },
 }, {
 	/* same phy as above, with just a different OUI */
@@ -95,8 +67,8 @@  static struct phy_driver bcm63xx_driver[] = {
 	.config_init	= bcm63xx_config_init,
 	.config_aneg	= genphy_config_aneg,
 	.read_status	= genphy_read_status,
-	.ack_interrupt	= bcm63xx_ack_interrupt,
-	.config_intr	= bcm63xx_config_intr,
+	.ack_interrupt	= bcm_phy_ack_intr,
+	.config_intr	= bcm_phy_config_intr,
 	.driver		= { .owner = THIS_MODULE },
 } };
 
diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c
index 6b701b3..efa31a6 100644
--- a/drivers/net/phy/bcm7xxx.c
+++ b/drivers/net/phy/bcm7xxx.c
@@ -12,12 +12,12 @@ 
 #include <linux/module.h>
 #include <linux/phy.h>
 #include <linux/delay.h>
+#include "bcm-phy-lib.h"
 #include <linux/bitops.h>
 #include <linux/brcmphy.h>
 #include <linux/mdio.h>
 
 /* Broadcom BCM7xxx internal PHY registers */
-#define MII_BCM7XXX_CHANNEL_WIDTH	0x2000
 
 /* 40nm only register definitions */
 #define MII_BCM7XXX_100TX_AUX_CTL	0x10
@@ -48,37 +48,13 @@ 
 
 #define CORE_EXPB0			0xb0
 
-static void phy_write_exp(struct phy_device *phydev,
-					u16 reg, u16 value)
-{
-	phy_write(phydev, MII_BCM54XX_EXP_SEL, MII_BCM54XX_EXP_SEL_ER | reg);
-	phy_write(phydev, MII_BCM54XX_EXP_DATA, value);
-}
-
-static void phy_write_misc(struct phy_device *phydev,
-					u16 reg, u16 chl, u16 value)
-{
-	int tmp;
-
-	phy_write(phydev, MII_BCM54XX_AUX_CTL, MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
-
-	tmp = phy_read(phydev, MII_BCM54XX_AUX_CTL);
-	tmp |= MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA;
-	phy_write(phydev, MII_BCM54XX_AUX_CTL, tmp);
-
-	tmp = (chl * MII_BCM7XXX_CHANNEL_WIDTH) | reg;
-	phy_write(phydev, MII_BCM54XX_EXP_SEL, tmp);
-
-	phy_write(phydev, MII_BCM54XX_EXP_DATA, value);
-}
-
 static void r_rc_cal_reset(struct phy_device *phydev)
 {
 	/* Reset R_CAL/RC_CAL Engine */
-	phy_write_exp(phydev, 0x00b0, 0x0010);
+	bcm_phy_write_exp(phydev, 0x00b0, 0x0010);
 
 	/* Disable Reset R_AL/RC_CAL Engine */
-	phy_write_exp(phydev, 0x00b0, 0x0000);
+	bcm_phy_write_exp(phydev, 0x00b0, 0x0000);
 }
 
 static int bcm7xxx_28nm_b0_afe_config_init(struct phy_device *phydev)
@@ -86,18 +62,18 @@  static int bcm7xxx_28nm_b0_afe_config_init(struct phy_device *phydev)
 	/* Increase VCO range to prevent unlocking problem of PLL at low
 	 * temp
 	 */
-	phy_write_misc(phydev, PLL_PLLCTRL_1, 0x0048);
+	bcm_phy_write_misc(phydev, PLL_PLLCTRL_1, 0x0048);
 
 	/* Change Ki to 011 */
-	phy_write_misc(phydev, PLL_PLLCTRL_2, 0x021b);
+	bcm_phy_write_misc(phydev, PLL_PLLCTRL_2, 0x021b);
 
 	/* Disable loading of TVCO buffer to bandgap, set bandgap trim
 	 * to 111
 	 */
-	phy_write_misc(phydev, PLL_PLLCTRL_4, 0x0e20);
+	bcm_phy_write_misc(phydev, PLL_PLLCTRL_4, 0x0e20);
 
 	/* Adjust bias current trim by -3 */
-	phy_write_misc(phydev, DSP_TAP10, 0x690b);
+	bcm_phy_write_misc(phydev, DSP_TAP10, 0x690b);
 
 	/* Switch to CORE_BASE1E */
 	phy_write(phydev, MII_BCM7XXX_CORE_BASE1E, 0xd);
@@ -105,19 +81,19 @@  static int bcm7xxx_28nm_b0_afe_config_init(struct phy_device *phydev)
 	r_rc_cal_reset(phydev);
 
 	/* write AFE_RXCONFIG_0 */
-	phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb19);
+	bcm_phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb19);
 
 	/* write AFE_RXCONFIG_1 */
-	phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9a3f);
+	bcm_phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9a3f);
 
 	/* write AFE_RX_LP_COUNTER */
-	phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0);
+	bcm_phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0);
 
 	/* write AFE_HPF_TRIM_OTHERS */
-	phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x000b);
+	bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x000b);
 
 	/* write AFTE_TX_CONFIG */
-	phy_write_misc(phydev, AFE_TX_CONFIG, 0x0800);
+	bcm_phy_write_misc(phydev, AFE_TX_CONFIG, 0x0800);
 
 	return 0;
 }
@@ -125,36 +101,36 @@  static int bcm7xxx_28nm_b0_afe_config_init(struct phy_device *phydev)
 static int bcm7xxx_28nm_d0_afe_config_init(struct phy_device *phydev)
 {
 	/* AFE_RXCONFIG_0 */
-	phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb15);
+	bcm_phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb15);
 
 	/* AFE_RXCONFIG_1 */
-	phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9b2f);
+	bcm_phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9b2f);
 
 	/* AFE_RXCONFIG_2, set rCal offset for HT=0 code and LT=-2 code */
-	phy_write_misc(phydev, AFE_RXCONFIG_2, 0x2003);
+	bcm_phy_write_misc(phydev, AFE_RXCONFIG_2, 0x2003);
 
 	/* AFE_RX_LP_COUNTER, set RX bandwidth to maximum */
-	phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0);
+	bcm_phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0);
 
 	/* AFE_TX_CONFIG, set 100BT Cfeed=011 to improve rise/fall time */
-	phy_write_misc(phydev, AFE_TX_CONFIG, 0x431);
+	bcm_phy_write_misc(phydev, AFE_TX_CONFIG, 0x431);
 
 	/* AFE_VDCA_ICTRL_0, set Iq=1101 instead of 0111 for AB symmetry */
-	phy_write_misc(phydev, AFE_VDCA_ICTRL_0, 0xa7da);
+	bcm_phy_write_misc(phydev, AFE_VDCA_ICTRL_0, 0xa7da);
 
 	/* AFE_VDAC_OTHERS_0, set 1000BT Cidac=010 for all ports */
-	phy_write_misc(phydev, AFE_VDAC_OTHERS_0, 0xa020);
+	bcm_phy_write_misc(phydev, AFE_VDAC_OTHERS_0, 0xa020);
 
 	/* AFE_HPF_TRIM_OTHERS, set 100Tx/10BT to -4.5% swing and set rCal
 	 * offset for HT=0 code
 	 */
-	phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x00e3);
+	bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x00e3);
 
 	/* CORE_BASE1E, force trim to overwrite and set I_ext trim to 0000 */
 	phy_write(phydev, MII_BCM7XXX_CORE_BASE1E, 0x0010);
 
 	/* DSP_TAP10, adjust bias current trim (+0% swing, +0 tick) */
-	phy_write_misc(phydev, DSP_TAP10, 0x011b);
+	bcm_phy_write_misc(phydev, DSP_TAP10, 0x011b);
 
 	/* Reset R_CAL/RC_CAL engine */
 	r_rc_cal_reset(phydev);
@@ -165,24 +141,24 @@  static int bcm7xxx_28nm_d0_afe_config_init(struct phy_device *phydev)
 static int bcm7xxx_28nm_e0_plus_afe_config_init(struct phy_device *phydev)
 {
 	/* AFE_RXCONFIG_1, provide more margin for INL/DNL measurement */
-	phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9b2f);
+	bcm_phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9b2f);
 
 	/* AFE_TX_CONFIG, set 100BT Cfeed=011 to improve rise/fall time */
-	phy_write_misc(phydev, AFE_TX_CONFIG, 0x431);
+	bcm_phy_write_misc(phydev, AFE_TX_CONFIG, 0x431);
 
 	/* AFE_VDCA_ICTRL_0, set Iq=1101 instead of 0111 for AB symmetry */
-	phy_write_misc(phydev, AFE_VDCA_ICTRL_0, 0xa7da);
+	bcm_phy_write_misc(phydev, AFE_VDCA_ICTRL_0, 0xa7da);
 
 	/* AFE_HPF_TRIM_OTHERS, set 100Tx/10BT to -4.5% swing and set rCal
 	 * offset for HT=0 code
 	 */
-	phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x00e3);
+	bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x00e3);
 
 	/* CORE_BASE1E, force trim to overwrite and set I_ext trim to 0000 */
 	phy_write(phydev, MII_BCM7XXX_CORE_BASE1E, 0x0010);
 
 	/* DSP_TAP10, adjust bias current trim (+0% swing, +0 tick) */
-	phy_write_misc(phydev, DSP_TAP10, 0x011b);
+	bcm_phy_write_misc(phydev, DSP_TAP10, 0x011b);
 
 	/* Reset R_CAL/RC_CAL engine */
 	r_rc_cal_reset(phydev);
@@ -190,53 +166,6 @@  static int bcm7xxx_28nm_e0_plus_afe_config_init(struct phy_device *phydev)
 	return 0;
 }
 
-static int bcm7xxx_apd_enable(struct phy_device *phydev)
-{
-	int val;
-
-	/* Enable powering down of the DLL during auto-power down */
-	val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_SCR3);
-	if (val < 0)
-		return val;
-
-	val |= BCM54XX_SHD_SCR3_DLLAPD_DIS;
-	bcm54xx_shadow_write(phydev, BCM54XX_SHD_SCR3, val);
-
-	/* Enable auto-power down */
-	val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_APD);
-	if (val < 0)
-		return val;
-
-	val |= BCM54XX_SHD_APD_EN;
-	return bcm54xx_shadow_write(phydev, BCM54XX_SHD_APD, val);
-}
-
-static int bcm7xxx_eee_enable(struct phy_device *phydev)
-{
-	int val;
-
-	val = phy_read_mmd_indirect(phydev, BRCM_CL45VEN_EEE_CONTROL,
-				    MDIO_MMD_AN, phydev->addr);
-	if (val < 0)
-		return val;
-
-	/* Enable general EEE feature at the PHY level */
-	val |= LPI_FEATURE_EN | LPI_FEATURE_EN_DIG1000X;
-
-	phy_write_mmd_indirect(phydev, BRCM_CL45VEN_EEE_CONTROL,
-			       MDIO_MMD_AN, phydev->addr, val);
-
-	/* Advertise supported modes */
-	val = phy_read_mmd_indirect(phydev, MDIO_AN_EEE_ADV,
-				    MDIO_MMD_AN, phydev->addr);
-
-	val |= (MDIO_AN_EEE_ADV_100TX | MDIO_AN_EEE_ADV_1000T);
-	phy_write_mmd_indirect(phydev, MDIO_AN_EEE_ADV,
-			       MDIO_MMD_AN, phydev->addr, val);
-
-	return 0;
-}
-
 static int bcm7xxx_28nm_config_init(struct phy_device *phydev)
 {
 	u8 rev = PHY_BRCM_7XXX_REV(phydev->dev_flags);
@@ -273,11 +202,11 @@  static int bcm7xxx_28nm_config_init(struct phy_device *phydev)
 	if (ret)
 		return ret;
 
-	ret = bcm7xxx_eee_enable(phydev);
+	ret = bcm_phy_enable_eee(phydev);
 	if (ret)
 		return ret;
 
-	return bcm7xxx_apd_enable(phydev);
+	return bcm_phy_enable_apd(phydev, true);
 }
 
 static int bcm7xxx_28nm_resume(struct phy_device *phydev)
diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
index 9c71295..07a6119 100644
--- a/drivers/net/phy/broadcom.c
+++ b/drivers/net/phy/broadcom.c
@@ -14,6 +14,7 @@ 
  *	2 of the License, or (at your option) any later version.
  */
 
+#include "bcm-phy-lib.h"
 #include <linux/module.h>
 #include <linux/phy.h>
 #include <linux/brcmphy.h>
@@ -29,39 +30,6 @@  MODULE_DESCRIPTION("Broadcom PHY driver");
 MODULE_AUTHOR("Maciej W. Rozycki");
 MODULE_LICENSE("GPL");
 
-/* Indirect register access functions for the Expansion Registers */
-static int bcm54xx_exp_read(struct phy_device *phydev, u16 regnum)
-{
-	int val;
-
-	val = phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum);
-	if (val < 0)
-		return val;
-
-	val = phy_read(phydev, MII_BCM54XX_EXP_DATA);
-
-	/* Restore default value.  It's O.K. if this write fails. */
-	phy_write(phydev, MII_BCM54XX_EXP_SEL, 0);
-
-	return val;
-}
-
-static int bcm54xx_exp_write(struct phy_device *phydev, u16 regnum, u16 val)
-{
-	int ret;
-
-	ret = phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum);
-	if (ret < 0)
-		return ret;
-
-	ret = phy_write(phydev, MII_BCM54XX_EXP_DATA, val);
-
-	/* Restore default value.  It's O.K. if this write fails. */
-	phy_write(phydev, MII_BCM54XX_EXP_SEL, 0);
-
-	return ret;
-}
-
 static int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val)
 {
 	return phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum | val);
@@ -72,28 +40,28 @@  static int bcm50610_a0_workaround(struct phy_device *phydev)
 {
 	int err;
 
-	err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH0,
+	err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_AADJ1CH0,
 				MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN |
 				MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF);
 	if (err < 0)
 		return err;
 
-	err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH3,
-					MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ);
+	err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_AADJ1CH3,
+				MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ);
 	if (err < 0)
 		return err;
 
-	err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP75,
+	err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP75,
 				MII_BCM54XX_EXP_EXP75_VDACCTRL);
 	if (err < 0)
 		return err;
 
-	err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP96,
+	err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP96,
 				MII_BCM54XX_EXP_EXP96_MYST);
 	if (err < 0)
 		return err;
 
-	err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP97,
+	err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP97,
 				MII_BCM54XX_EXP_EXP97_MYST);
 
 	return err;
@@ -114,7 +82,7 @@  static int bcm54xx_phydsp_config(struct phy_device *phydev)
 	if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
 	    BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) {
 		/* Clear bit 9 to fix a phy interop issue. */
-		err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP08,
+		err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP08,
 					MII_BCM54XX_EXP_EXP08_RJCT_2MHZ);
 		if (err < 0)
 			goto error;
@@ -129,12 +97,12 @@  static int bcm54xx_phydsp_config(struct phy_device *phydev)
 	if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM57780) {
 		int val;
 
-		val = bcm54xx_exp_read(phydev, MII_BCM54XX_EXP_EXP75);
+		val = bcm_phy_read_exp(phydev, MII_BCM54XX_EXP_EXP75);
 		if (val < 0)
 			goto error;
 
 		val |= MII_BCM54XX_EXP_EXP75_CM_OSC;
-		err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP75, val);
+		err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP75, val);
 	}
 
 error:
@@ -159,7 +127,7 @@  static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev)
 	    BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610M)
 		return;
 
-	val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_SCR3);
+	val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR3);
 	if (val < 0)
 		return;
 
@@ -190,9 +158,9 @@  static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev)
 		val |= BCM54XX_SHD_SCR3_TRDDAPD;
 
 	if (orig != val)
-		bcm54xx_shadow_write(phydev, BCM54XX_SHD_SCR3, val);
+		bcm_phy_write_shadow(phydev, BCM54XX_SHD_SCR3, val);
 
-	val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_APD);
+	val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_APD);
 	if (val < 0)
 		return;
 
@@ -204,7 +172,7 @@  static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev)
 		val &= ~BCM54XX_SHD_APD_EN;
 
 	if (orig != val)
-		bcm54xx_shadow_write(phydev, BCM54XX_SHD_APD, val);
+		bcm_phy_write_shadow(phydev, BCM54XX_SHD_APD, val);
 }
 
 static int bcm54xx_config_init(struct phy_device *phydev)
@@ -232,7 +200,7 @@  static int bcm54xx_config_init(struct phy_device *phydev)
 	if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
 	     BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) &&
 	    (phydev->dev_flags & PHY_BRCM_CLEAR_RGMII_MODE))
-		bcm54xx_shadow_write(phydev, BCM54XX_SHD_RGMII_MODE, 0);
+		bcm_phy_write_shadow(phydev, BCM54XX_SHD_RGMII_MODE, 0);
 
 	if ((phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) ||
 	    (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY) ||
@@ -254,8 +222,8 @@  static int bcm5482_config_init(struct phy_device *phydev)
 		/*
 		 * Enable secondary SerDes and its use as an LED source
 		 */
-		reg = bcm54xx_shadow_read(phydev, BCM5482_SHD_SSD);
-		bcm54xx_shadow_write(phydev, BCM5482_SHD_SSD,
+		reg = bcm_phy_read_shadow(phydev, BCM5482_SHD_SSD);
+		bcm_phy_write_shadow(phydev, BCM5482_SHD_SSD,
 				     reg |
 				     BCM5482_SHD_SSD_LEDM |
 				     BCM5482_SHD_SSD_EN);
@@ -264,10 +232,10 @@  static int bcm5482_config_init(struct phy_device *phydev)
 		 * Enable SGMII slave mode and auto-detection
 		 */
 		reg = BCM5482_SSD_SGMII_SLAVE | MII_BCM54XX_EXP_SEL_SSD;
-		err = bcm54xx_exp_read(phydev, reg);
+		err = bcm_phy_read_exp(phydev, reg);
 		if (err < 0)
 			return err;
-		err = bcm54xx_exp_write(phydev, reg, err |
+		err = bcm_phy_write_exp(phydev, reg, err |
 					BCM5482_SSD_SGMII_SLAVE_EN |
 					BCM5482_SSD_SGMII_SLAVE_AD);
 		if (err < 0)
@@ -277,10 +245,10 @@  static int bcm5482_config_init(struct phy_device *phydev)
 		 * Disable secondary SerDes powerdown
 		 */
 		reg = BCM5482_SSD_1000BX_CTL | MII_BCM54XX_EXP_SEL_SSD;
-		err = bcm54xx_exp_read(phydev, reg);
+		err = bcm_phy_read_exp(phydev, reg);
 		if (err < 0)
 			return err;
-		err = bcm54xx_exp_write(phydev, reg,
+		err = bcm_phy_write_exp(phydev, reg,
 					err & ~BCM5482_SSD_1000BX_CTL_PWRDOWN);
 		if (err < 0)
 			return err;
@@ -288,15 +256,15 @@  static int bcm5482_config_init(struct phy_device *phydev)
 		/*
 		 * Select 1000BASE-X register set (primary SerDes)
 		 */
-		reg = bcm54xx_shadow_read(phydev, BCM5482_SHD_MODE);
-		bcm54xx_shadow_write(phydev, BCM5482_SHD_MODE,
+		reg = bcm_phy_read_shadow(phydev, BCM5482_SHD_MODE);
+		bcm_phy_write_shadow(phydev, BCM5482_SHD_MODE,
 				     reg | BCM5482_SHD_MODE_1000BX);
 
 		/*
 		 * LED1=ACTIVITYLED, LED3=LINKSPD[2]
 		 * (Use LED1 as secondary SerDes ACTIVITY LED)
 		 */
-		bcm54xx_shadow_write(phydev, BCM5482_SHD_LEDS1,
+		bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1,
 			BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_ACTIVITYLED) |
 			BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_LINKSPD2));
 
@@ -334,35 +302,6 @@  static int bcm5482_read_status(struct phy_device *phydev)
 	return err;
 }
 
-static int bcm54xx_ack_interrupt(struct phy_device *phydev)
-{
-	int reg;
-
-	/* Clear pending interrupts.  */
-	reg = phy_read(phydev, MII_BCM54XX_ISR);
-	if (reg < 0)
-		return reg;
-
-	return 0;
-}
-
-static int bcm54xx_config_intr(struct phy_device *phydev)
-{
-	int reg, err;
-
-	reg = phy_read(phydev, MII_BCM54XX_ECR);
-	if (reg < 0)
-		return reg;
-
-	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
-		reg &= ~MII_BCM54XX_ECR_IM;
-	else
-		reg |= MII_BCM54XX_ECR_IM;
-
-	err = phy_write(phydev, MII_BCM54XX_ECR, reg);
-	return err;
-}
-
 static int bcm5481_config_aneg(struct phy_device *phydev)
 {
 	int ret;
@@ -519,8 +458,8 @@  static struct phy_driver broadcom_drivers[] = {
 	.config_init	= bcm54xx_config_init,
 	.config_aneg	= genphy_config_aneg,
 	.read_status	= genphy_read_status,
-	.ack_interrupt	= bcm54xx_ack_interrupt,
-	.config_intr	= bcm54xx_config_intr,
+	.ack_interrupt	= bcm_phy_ack_intr,
+	.config_intr	= bcm_phy_config_intr,
 	.driver		= { .owner = THIS_MODULE },
 }, {
 	.phy_id		= PHY_ID_BCM5421,
@@ -532,8 +471,8 @@  static struct phy_driver broadcom_drivers[] = {
 	.config_init	= bcm54xx_config_init,
 	.config_aneg	= genphy_config_aneg,
 	.read_status	= genphy_read_status,
-	.ack_interrupt	= bcm54xx_ack_interrupt,
-	.config_intr	= bcm54xx_config_intr,
+	.ack_interrupt	= bcm_phy_ack_intr,
+	.config_intr	= bcm_phy_config_intr,
 	.driver		= { .owner = THIS_MODULE },
 }, {
 	.phy_id		= PHY_ID_BCM5461,
@@ -545,8 +484,8 @@  static struct phy_driver broadcom_drivers[] = {
 	.config_init	= bcm54xx_config_init,
 	.config_aneg	= genphy_config_aneg,
 	.read_status	= genphy_read_status,
-	.ack_interrupt	= bcm54xx_ack_interrupt,
-	.config_intr	= bcm54xx_config_intr,
+	.ack_interrupt	= bcm_phy_ack_intr,
+	.config_intr	= bcm_phy_config_intr,
 	.driver		= { .owner = THIS_MODULE },
 }, {
 	.phy_id		= PHY_ID_BCM54616S,
@@ -558,8 +497,8 @@  static struct phy_driver broadcom_drivers[] = {
 	.config_init	= bcm54xx_config_init,
 	.config_aneg	= genphy_config_aneg,
 	.read_status	= genphy_read_status,
-	.ack_interrupt	= bcm54xx_ack_interrupt,
-	.config_intr	= bcm54xx_config_intr,
+	.ack_interrupt	= bcm_phy_ack_intr,
+	.config_intr	= bcm_phy_config_intr,
 	.driver		= { .owner = THIS_MODULE },
 }, {
 	.phy_id		= PHY_ID_BCM5464,
@@ -571,8 +510,8 @@  static struct phy_driver broadcom_drivers[] = {
 	.config_init	= bcm54xx_config_init,
 	.config_aneg	= genphy_config_aneg,
 	.read_status	= genphy_read_status,
-	.ack_interrupt	= bcm54xx_ack_interrupt,
-	.config_intr	= bcm54xx_config_intr,
+	.ack_interrupt	= bcm_phy_ack_intr,
+	.config_intr	= bcm_phy_config_intr,
 	.driver		= { .owner = THIS_MODULE },
 }, {
 	.phy_id		= PHY_ID_BCM5481,
@@ -584,8 +523,8 @@  static struct phy_driver broadcom_drivers[] = {
 	.config_init	= bcm54xx_config_init,
 	.config_aneg	= bcm5481_config_aneg,
 	.read_status	= genphy_read_status,
-	.ack_interrupt	= bcm54xx_ack_interrupt,
-	.config_intr	= bcm54xx_config_intr,
+	.ack_interrupt	= bcm_phy_ack_intr,
+	.config_intr	= bcm_phy_config_intr,
 	.driver		= { .owner = THIS_MODULE },
 }, {
 	.phy_id		= PHY_ID_BCM5482,
@@ -597,8 +536,8 @@  static struct phy_driver broadcom_drivers[] = {
 	.config_init	= bcm5482_config_init,
 	.config_aneg	= genphy_config_aneg,
 	.read_status	= bcm5482_read_status,
-	.ack_interrupt	= bcm54xx_ack_interrupt,
-	.config_intr	= bcm54xx_config_intr,
+	.ack_interrupt	= bcm_phy_ack_intr,
+	.config_intr	= bcm_phy_config_intr,
 	.driver		= { .owner = THIS_MODULE },
 }, {
 	.phy_id		= PHY_ID_BCM50610,
@@ -610,8 +549,8 @@  static struct phy_driver broadcom_drivers[] = {
 	.config_init	= bcm54xx_config_init,
 	.config_aneg	= genphy_config_aneg,
 	.read_status	= genphy_read_status,
-	.ack_interrupt	= bcm54xx_ack_interrupt,
-	.config_intr	= bcm54xx_config_intr,
+	.ack_interrupt	= bcm_phy_ack_intr,
+	.config_intr	= bcm_phy_config_intr,
 	.driver		= { .owner = THIS_MODULE },
 }, {
 	.phy_id		= PHY_ID_BCM50610M,
@@ -623,8 +562,8 @@  static struct phy_driver broadcom_drivers[] = {
 	.config_init	= bcm54xx_config_init,
 	.config_aneg	= genphy_config_aneg,
 	.read_status	= genphy_read_status,
-	.ack_interrupt	= bcm54xx_ack_interrupt,
-	.config_intr	= bcm54xx_config_intr,
+	.ack_interrupt	= bcm_phy_ack_intr,
+	.config_intr	= bcm_phy_config_intr,
 	.driver		= { .owner = THIS_MODULE },
 }, {
 	.phy_id		= PHY_ID_BCM57780,
@@ -636,8 +575,8 @@  static struct phy_driver broadcom_drivers[] = {
 	.config_init	= bcm54xx_config_init,
 	.config_aneg	= genphy_config_aneg,
 	.read_status	= genphy_read_status,
-	.ack_interrupt	= bcm54xx_ack_interrupt,
-	.config_intr	= bcm54xx_config_intr,
+	.ack_interrupt	= bcm_phy_ack_intr,
+	.config_intr	= bcm_phy_config_intr,
 	.driver		= { .owner = THIS_MODULE },
 }, {
 	.phy_id		= PHY_ID_BCMAC131,
diff --git a/include/linux/brcmphy.h b/include/linux/brcmphy.h
index 697ca77..6a53ab9 100644
--- a/include/linux/brcmphy.h
+++ b/include/linux/brcmphy.h
@@ -138,7 +138,10 @@ 
 
 /* 01010: Auto Power-Down */
 #define BCM54XX_SHD_APD			0x0a
+#define  BCM_APD_CLR_MASK		0xFE9F /* clear bits 5, 6 & 8 */
 #define  BCM54XX_SHD_APD_EN		0x0020
+#define  BCM_NO_ANEG_APD_EN		0x0060 /* bits 5 & 6 */
+#define  BCM_APD_SINGLELP_EN	0x0100 /* Bit 8 */
 
 #define BCM5482_SHD_LEDS1	0x0d	/* 01101: LED Selector 1 */
 					/* LED3 / ~LINKSPD[2] selector */
@@ -209,25 +212,6 @@ 
 #define MII_BRCM_FET_SHDW_AUXSTAT2	0x1b	/* Auxiliary status 2 */
 #define MII_BRCM_FET_SHDW_AS2_APDE	0x0020	/* Auto power down enable */
 
-/*
- * Indirect register access functions for the 1000BASE-T/100BASE-TX/10BASE-T
- * 0x1c shadow registers.
- */
-static inline int bcm54xx_shadow_read(struct phy_device *phydev, u16 shadow)
-{
-	phy_write(phydev, MII_BCM54XX_SHD, MII_BCM54XX_SHD_VAL(shadow));
-	return MII_BCM54XX_SHD_DATA(phy_read(phydev, MII_BCM54XX_SHD));
-}
-
-static inline int bcm54xx_shadow_write(struct phy_device *phydev, u16 shadow,
-				       u16 val)
-{
-	return phy_write(phydev, MII_BCM54XX_SHD,
-			 MII_BCM54XX_SHD_WRITE |
-			 MII_BCM54XX_SHD_VAL(shadow) |
-			 MII_BCM54XX_SHD_DATA(val));
-}
-
 #define BRCM_CL45VEN_EEE_CONTROL	0x803d
 #define LPI_FEATURE_EN			0x8000
 #define LPI_FEATURE_EN_DIG1000X		0x4000