diff options
Diffstat (limited to 'drivers/net/phy/adin.c')
-rw-r--r-- | drivers/net/phy/adin.c | 68 |
1 files changed, 66 insertions, 2 deletions
diff --git a/drivers/net/phy/adin.c b/drivers/net/phy/adin.c index 51c0d17577de..131b7f85ae32 100644 --- a/drivers/net/phy/adin.c +++ b/drivers/net/phy/adin.c @@ -40,6 +40,16 @@ #define ADIN1300_PHY_STATUS1 0x001a #define ADIN1300_PAIR_01_SWAP BIT(11) +/* EEE register addresses, accessible via Clause 22 access using + * ADIN1300_MII_EXT_REG_PTR & ADIN1300_MII_EXT_REG_DATA. + * The bit-fields are the same as specified by IEEE for EEE. + */ +#define ADIN1300_EEE_CAP_REG 0x8000 +#define ADIN1300_EEE_ADV_REG 0x8001 +#define ADIN1300_EEE_LPABLE_REG 0x8002 +#define ADIN1300_CLOCK_STOP_REG 0x9400 +#define ADIN1300_LPI_WAKE_ERR_CNT_REG 0xa000 + #define ADIN1300_GE_RGMII_CFG_REG 0xff23 #define ADIN1300_GE_RGMII_RX_MSK GENMASK(8, 6) #define ADIN1300_GE_RGMII_RX_SEL(x) \ @@ -101,6 +111,26 @@ static const struct adin_cfg_reg_map adin_rmii_fifo_depths[] = { { }, }; +/** + * struct adin_clause45_mmd_map - map to convert Clause 45 regs to Clause 22 + * @devad device address used in Clause 45 access + * @cl45_regnum register address defined by Clause 45 + * @adin_regnum equivalent register address accessible via Clause 22 + */ +struct adin_clause45_mmd_map { + int devad; + u16 cl45_regnum; + u16 adin_regnum; +}; + +static struct adin_clause45_mmd_map adin_clause45_mmd_map[] = { + { MDIO_MMD_PCS, MDIO_PCS_EEE_ABLE, ADIN1300_EEE_CAP_REG }, + { MDIO_MMD_AN, MDIO_AN_EEE_LPABLE, ADIN1300_EEE_LPABLE_REG }, + { MDIO_MMD_AN, MDIO_AN_EEE_ADV, ADIN1300_EEE_ADV_REG }, + { MDIO_MMD_PCS, MDIO_CTRL1, ADIN1300_CLOCK_STOP_REG }, + { MDIO_MMD_PCS, MDIO_PCS_EEE_WK_ERR, ADIN1300_LPI_WAKE_ERR_CNT_REG }, +}; + static int adin_lookup_reg_value(const struct adin_cfg_reg_map *tbl, int cfg) { size_t i; @@ -251,13 +281,41 @@ static int adin_phy_config_intr(struct phy_device *phydev) ADIN1300_INT_MASK_EN); } +static int adin_cl45_to_adin_reg(struct phy_device *phydev, int devad, + u16 cl45_regnum) +{ + struct adin_clause45_mmd_map *m; + int i; + + if (devad == MDIO_MMD_VEND1) + return cl45_regnum; + + for (i = 0; i < ARRAY_SIZE(adin_clause45_mmd_map); i++) { + m = &adin_clause45_mmd_map[i]; + if (m->devad == devad && m->cl45_regnum == cl45_regnum) + return m->adin_regnum; + } + + phydev_err(phydev, + "No translation available for devad: %d reg: %04x\n", + devad, cl45_regnum); + + return -EINVAL; +} + static int adin_read_mmd(struct phy_device *phydev, int devad, u16 regnum) { struct mii_bus *bus = phydev->mdio.bus; int phy_addr = phydev->mdio.addr; + int adin_regnum; int err; - err = __mdiobus_write(bus, phy_addr, ADIN1300_MII_EXT_REG_PTR, regnum); + adin_regnum = adin_cl45_to_adin_reg(phydev, devad, regnum); + if (adin_regnum < 0) + return adin_regnum; + + err = __mdiobus_write(bus, phy_addr, ADIN1300_MII_EXT_REG_PTR, + adin_regnum); if (err) return err; @@ -269,9 +327,15 @@ static int adin_write_mmd(struct phy_device *phydev, int devad, u16 regnum, { struct mii_bus *bus = phydev->mdio.bus; int phy_addr = phydev->mdio.addr; + int adin_regnum; int err; - err = __mdiobus_write(bus, phy_addr, ADIN1300_MII_EXT_REG_PTR, regnum); + adin_regnum = adin_cl45_to_adin_reg(phydev, devad, regnum); + if (adin_regnum < 0) + return adin_regnum; + + err = __mdiobus_write(bus, phy_addr, ADIN1300_MII_EXT_REG_PTR, + adin_regnum); if (err) return err; |