Thread (31 messages) flat view 31 messages, 4 authors, 2021-02-10
STALE2002d

Revision v1 of 4 in this series.

Revisions (4)
  1. v1 current
  2. v2 [diff vs current]
  3. v2 [diff vs current]
  4. v4 [diff vs current]

[PATCH net-next 5/9] net: phy: icplus: add IP101A/IP101G model detection

From: Michael Walle <hidden>
Date: 2021-02-09 16:44:12
Also in: lkml
Subsystem: ethernet phy library, networking drivers, the rest · Maintainers: Andrew Lunn, Heiner Kallweit, Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds

Unfortunately, the IP101A and IP101G share the same PHY identifier.
While most of the functions are somewhat backwards compatible, there is
for example the APS_EN bit on the IP101A but on the IP101G this bit
reserved. Also, the IP101G has many more functionalities.

Deduce the model by accessing the page select register which - according
to the datasheet - is not available on the IP101A. If this register is
writable, assume we have an IP101G.

Signed-off-by: Michael Walle <redacted>
---
 drivers/net/phy/icplus.c | 43 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 42 insertions(+), 1 deletion(-)
diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c
index 036bac628b11..189a9a34ed5f 100644
--- a/drivers/net/phy/icplus.c
+++ b/drivers/net/phy/icplus.c
@@ -44,6 +44,8 @@ MODULE_LICENSE("GPL");
 #define IP101A_G_IRQ_DUPLEX_CHANGE	BIT(1)
 #define IP101A_G_IRQ_LINK_CHANGE	BIT(0)
 
+#define IP101G_PAGE_CONTROL				0x14
+#define IP101G_PAGE_CONTROL_MASK			GENMASK(4, 0)
 #define IP101G_DIGITAL_IO_SPEC_CTRL			0x1d
 #define IP101G_DIGITAL_IO_SPEC_CTRL_SEL_INTR32		BIT(2)
 
@@ -61,8 +63,14 @@ enum ip101gr_sel_intr32 {
 	IP101GR_SEL_INTR32_RXER,
 };
 
+enum ip101_model {
+	IP101A,
+	IP101G,
+};
+
 struct ip101a_g_phy_priv {
 	enum ip101gr_sel_intr32 sel_intr32;
+	enum ip101_model model;
 };
 
 static int ip175c_config_init(struct phy_device *phydev)
@@ -175,6 +183,39 @@ static int ip175c_config_aneg(struct phy_device *phydev)
 	return 0;
 }
 
+/* The IP101A and the IP101G share the same PHY identifier.The IP101G seems to
+ * be a successor of the IP101A and implements more functions. Amongst other
+ * things a page select register, which is not available on the IP101. Use this
+ * to distinguish these two.
+ */
+static int ip101a_g_detect_model(struct phy_device *phydev)
+{
+	struct ip101a_g_phy_priv *priv = phydev->priv;
+	int oldval, ret;
+
+	oldval = phy_read(phydev, IP101G_PAGE_CONTROL);
+	if (oldval < 0)
+		return oldval;
+
+	ret = phy_write(phydev, IP101G_PAGE_CONTROL, 0xffff);
+	if (ret)
+		return ret;
+
+	ret = phy_read(phydev, IP101G_PAGE_CONTROL);
+	if (ret < 0)
+		return ret;
+
+	if (ret == IP101G_PAGE_CONTROL_MASK)
+		priv->model = IP101G;
+	else
+		priv->model = IP101A;
+
+	phydev_dbg(phydev, "Detected %s\n",
+		   priv->model == IP101G ? "IP101G" : "IP101A");
+
+	return phy_write(phydev, IP101G_PAGE_CONTROL, oldval);
+}
+
 static int ip101a_g_probe(struct phy_device *phydev)
 {
 	struct device *dev = &phydev->mdio.dev;
@@ -203,7 +244,7 @@ static int ip101a_g_probe(struct phy_device *phydev)
 
 	phydev->priv = priv;
 
-	return 0;
+	return ip101a_g_detect_model(phydev);
 }
 
 static int ip101a_g_config_init(struct phy_device *phydev)
-- 
2.20.1
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help