diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index e56e269a6eb3..c94e2a27446a 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -942,7 +942,7 @@ static inline void mmd_phy_indirect(struct mii_bus *bus, int prtad, int devad, /** * phy_read_mmd_indirect - reads data from the MMD registers - * @bus: the target MII bus + * @phydev: The PHY device bus * @prtad: MMD Address * @devad: MMD DEVAD * @addr: PHY address on the MII bus @@ -955,18 +955,26 @@ static inline void mmd_phy_indirect(struct mii_bus *bus, int prtad, int devad, * 3) Write reg 13 // MMD Data Command for MMD DEVAD * 3) Read reg 14 // Read MMD data */ -static int phy_read_mmd_indirect(struct mii_bus *bus, int prtad, int devad, - int addr) +static int phy_read_mmd_indirect(struct phy_device *phydev, int prtad, + int devad, int addr) { - mmd_phy_indirect(bus, prtad, devad, addr); + struct phy_driver *phydrv = phydev->drv; + int value = -1; - /* Read the content of the MMD's selected register */ - return bus->read(bus, addr, MII_MMD_DATA); + if (phydrv->read_mmd_indirect == NULL) { + mmd_phy_indirect(phydev->bus, prtad, devad, addr); + + /* Read the content of the MMD's selected register */ + value = phydev->bus->read(phydev->bus, addr, MII_MMD_DATA); + } else { + value = phydrv->read_mmd_indirect(phydev, prtad, devad, addr); + } + return value; } /** * phy_write_mmd_indirect - writes data to the MMD registers - * @bus: the target MII bus + * @phydev: The PHY device * @prtad: MMD Address * @devad: MMD DEVAD * @addr: PHY address on the MII bus @@ -980,13 +988,19 @@ static int phy_read_mmd_indirect(struct mii_bus *bus, int prtad, int devad, * 3) Write reg 13 // MMD Data Command for MMD DEVAD * 3) Write reg 14 // Write MMD data */ -static void phy_write_mmd_indirect(struct mii_bus *bus, int prtad, int devad, - int addr, u32 data) +static void phy_write_mmd_indirect(struct phy_device *phydev, int prtad, + int devad, int addr, u32 data) { - mmd_phy_indirect(bus, prtad, devad, addr); + struct phy_driver *phydrv = phydev->drv; - /* Write the data into MMD's selected register */ - bus->write(bus, addr, MII_MMD_DATA, data); + if (phydrv->write_mmd_indirect == NULL) { + mmd_phy_indirect(phydev->bus, prtad, devad, addr); + + /* Write the data into MMD's selected register */ + phydev->bus->write(phydev->bus, addr, MII_MMD_DATA, data); + } else { + phydrv->write_mmd_indirect(phydev, prtad, devad, addr, data); + } } /** @@ -1020,7 +1034,7 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable) return status; /* First check if the EEE ability is supported */ - eee_cap = phy_read_mmd_indirect(phydev->bus, MDIO_PCS_EEE_ABLE, + eee_cap = phy_read_mmd_indirect(phydev, MDIO_PCS_EEE_ABLE, MDIO_MMD_PCS, phydev->addr); if (eee_cap < 0) return eee_cap; @@ -1032,12 +1046,12 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable) /* Check which link settings negotiated and verify it in * the EEE advertising registers. */ - eee_lp = phy_read_mmd_indirect(phydev->bus, MDIO_AN_EEE_LPABLE, + eee_lp = phy_read_mmd_indirect(phydev, MDIO_AN_EEE_LPABLE, MDIO_MMD_AN, phydev->addr); if (eee_lp < 0) return eee_lp; - eee_adv = phy_read_mmd_indirect(phydev->bus, MDIO_AN_EEE_ADV, + eee_adv = phy_read_mmd_indirect(phydev, MDIO_AN_EEE_ADV, MDIO_MMD_AN, phydev->addr); if (eee_adv < 0) return eee_adv; @@ -1052,15 +1066,16 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable) /* Configure the PHY to stop receiving xMII * clock while it is signaling LPI. */ - int val = phy_read_mmd_indirect(phydev->bus, MDIO_CTRL1, + int val = phy_read_mmd_indirect(phydev, MDIO_CTRL1, MDIO_MMD_PCS, phydev->addr); if (val < 0) return val; val |= MDIO_PCS_CTRL1_CLKSTOP_EN; - phy_write_mmd_indirect(phydev->bus, MDIO_CTRL1, - MDIO_MMD_PCS, phydev->addr, val); + phy_write_mmd_indirect(phydev, MDIO_CTRL1, + MDIO_MMD_PCS, phydev->addr, + val); } return 0; /* EEE supported */ @@ -1079,7 +1094,7 @@ EXPORT_SYMBOL(phy_init_eee); */ int phy_get_eee_err(struct phy_device *phydev) { - return phy_read_mmd_indirect(phydev->bus, MDIO_PCS_EEE_WK_ERR, + return phy_read_mmd_indirect(phydev, MDIO_PCS_EEE_WK_ERR, MDIO_MMD_PCS, phydev->addr); } EXPORT_SYMBOL(phy_get_eee_err); @@ -1097,21 +1112,21 @@ int phy_ethtool_get_eee(struct phy_device *phydev, struct ethtool_eee *data) int val; /* Get Supported EEE */ - val = phy_read_mmd_indirect(phydev->bus, MDIO_PCS_EEE_ABLE, + val = phy_read_mmd_indirect(phydev, MDIO_PCS_EEE_ABLE, MDIO_MMD_PCS, phydev->addr); if (val < 0) return val; data->supported = mmd_eee_cap_to_ethtool_sup_t(val); /* Get advertisement EEE */ - val = phy_read_mmd_indirect(phydev->bus, MDIO_AN_EEE_ADV, + val = phy_read_mmd_indirect(phydev, MDIO_AN_EEE_ADV, MDIO_MMD_AN, phydev->addr); if (val < 0) return val; data->advertised = mmd_eee_adv_to_ethtool_adv_t(val); /* Get LP advertisement EEE */ - val = phy_read_mmd_indirect(phydev->bus, MDIO_AN_EEE_LPABLE, + val = phy_read_mmd_indirect(phydev, MDIO_AN_EEE_LPABLE, MDIO_MMD_AN, phydev->addr); if (val < 0) return val; @@ -1132,7 +1147,7 @@ int phy_ethtool_set_eee(struct phy_device *phydev, struct ethtool_eee *data) { int val = ethtool_adv_to_mmd_eee_adv_t(data->advertised); - phy_write_mmd_indirect(phydev->bus, MDIO_AN_EEE_ADV, MDIO_MMD_AN, + phy_write_mmd_indirect(phydev, MDIO_AN_EEE_ADV, MDIO_MMD_AN, phydev->addr, val); return 0; diff --git a/include/linux/phy.h b/include/linux/phy.h index 68041446c450..ed39956b5613 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -545,6 +545,24 @@ struct phy_driver { */ void (*link_change_notify)(struct phy_device *dev); + /* A function provided by a phy specific driver to override the + * the PHY driver framework support for reading a MMD register + * from the PHY. If not supported, return -1. This function is + * optional for PHY specific drivers, if not provided then the + * default MMD read function is used by the PHY framework. + */ + int (*read_mmd_indirect)(struct phy_device *dev, int ptrad, + int devnum, int regnum); + + /* A function provided by a phy specific driver to override the + * the PHY driver framework support for writing a MMD register + * from the PHY. This function is optional for PHY specific drivers, + * if not provided then the default MMD read function is used by + * the PHY framework. + */ + void (*write_mmd_indirect)(struct phy_device *dev, int ptrad, + int devnum, int regnum, u32 val); + struct device_driver driver; }; #define to_phy_driver(d) container_of(d, struct phy_driver, driver)