summaryrefslogtreecommitdiff
path: root/drivers/net/phy/adin.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/phy/adin.c')
-rw-r--r--drivers/net/phy/adin.c68
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;