net: phy: adin1100: Add SQI support
authorAlexandru Tachici <alexandru.tachici@analog.com>
Fri, 29 Apr 2022 15:34:36 +0000 (18:34 +0300)
committerDavid S. Miller <davem@davemloft.net>
Sun, 1 May 2022 16:45:35 +0000 (17:45 +0100)
Determine the SQI from MSE using a predefined table
for the 10BASE-T1L.

Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Alexandru Tachici <alexandru.tachici@analog.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/phy/adin1100.c

index f20bbef37239239439acc967c1a9f383b1dc9cb1..b6d139501199016e3271add67f69aca5b7f47010 100644 (file)
 #define   ADIN_CRSM_SFT_PD_RDY                 BIT(1)
 #define   ADIN_CRSM_SYS_RDY                    BIT(0)
 
+#define ADIN_MSE_VAL                           0x830B
+
+#define ADIN_SQI_MAX   7
+
+struct adin_mse_sqi_range {
+       u16 start;
+       u16 end;
+};
+
+static const struct adin_mse_sqi_range adin_mse_sqi_map[] = {
+       { 0x0A74, 0xFFFF },
+       { 0x084E, 0x0A74 },
+       { 0x0698, 0x084E },
+       { 0x053D, 0x0698 },
+       { 0x0429, 0x053D },
+       { 0x034E, 0x0429 },
+       { 0x02A0, 0x034E },
+       { 0x0000, 0x02A0 },
+};
+
 /**
  * struct adin_priv - ADIN PHY driver private data
  * @tx_level_2v4_able:         set if the PHY supports 2.4V TX levels (10BASE-T1L)
@@ -199,6 +219,36 @@ static int adin_get_features(struct phy_device *phydev)
        return genphy_c45_pma_read_abilities(phydev);
 }
 
+static int adin_get_sqi(struct phy_device *phydev)
+{
+       u16 mse_val;
+       int sqi;
+       int ret;
+
+       ret = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_STAT1);
+       if (ret < 0)
+               return ret;
+       else if (!(ret & MDIO_STAT1_LSTATUS))
+               return 0;
+
+       ret = phy_read_mmd(phydev, MDIO_STAT1, ADIN_MSE_VAL);
+       if (ret < 0)
+               return ret;
+
+       mse_val = 0xFFFF & ret;
+       for (sqi = 0; sqi < ARRAY_SIZE(adin_mse_sqi_map); sqi++) {
+               if (mse_val >= adin_mse_sqi_map[sqi].start && mse_val <= adin_mse_sqi_map[sqi].end)
+                       return sqi;
+       }
+
+       return -EINVAL;
+}
+
+static int adin_get_sqi_max(struct phy_device *phydev)
+{
+       return ADIN_SQI_MAX;
+}
+
 static int adin_probe(struct phy_device *phydev)
 {
        struct device *dev = &phydev->mdio.dev;
@@ -225,6 +275,8 @@ static struct phy_driver adin_driver[] = {
                .set_loopback           = adin_set_loopback,
                .suspend                = adin_suspend,
                .resume                 = adin_resume,
+               .get_sqi                = adin_get_sqi,
+               .get_sqi_max            = adin_get_sqi_max,
        },
 };