net: phy: micrel: Add support for LAN8804 PHY
authorHoratiu Vultur <horatiu.vultur@microchip.com>
Tue, 28 Sep 2021 18:45:19 +0000 (20:45 +0200)
committerDavid S. Miller <davem@davemloft.net>
Wed, 29 Sep 2021 09:54:50 +0000 (10:54 +0100)
The LAN8804 PHY has same features as that of LAN8814 PHY except that it
doesn't support 1588, SyncE or Q-USGMII.

This PHY is found inside the LAN966X switches.

Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/phy/micrel.c
include/linux/micrel_phy.h

index 5c928f8..c330a5a 100644 (file)
@@ -1537,6 +1537,65 @@ static int ksz886x_cable_test_get_status(struct phy_device *phydev,
        return ret;
 }
 
+#define LAN_EXT_PAGE_ACCESS_CONTROL                    0x16
+#define LAN_EXT_PAGE_ACCESS_ADDRESS_DATA               0x17
+#define LAN_EXT_PAGE_ACCESS_CTRL_EP_FUNC               0x4000
+
+#define LAN8804_ALIGN_SWAP                             0x4a
+#define LAN8804_ALIGN_TX_A_B_SWAP                      0x1
+#define LAN8804_ALIGN_TX_A_B_SWAP_MASK                 GENMASK(2, 0)
+#define LAN8814_CLOCK_MANAGEMENT                       0xd
+#define LAN8814_LINK_QUALITY                           0x8e
+
+static int lanphy_read_page_reg(struct phy_device *phydev, int page, u32 addr)
+{
+       u32 data;
+
+       phy_write(phydev, LAN_EXT_PAGE_ACCESS_CONTROL, page);
+       phy_write(phydev, LAN_EXT_PAGE_ACCESS_ADDRESS_DATA, addr);
+       phy_write(phydev, LAN_EXT_PAGE_ACCESS_CONTROL,
+                 (page | LAN_EXT_PAGE_ACCESS_CTRL_EP_FUNC));
+       data = phy_read(phydev, LAN_EXT_PAGE_ACCESS_ADDRESS_DATA);
+
+       return data;
+}
+
+static int lanphy_write_page_reg(struct phy_device *phydev, int page, u16 addr,
+                                u16 val)
+{
+       phy_write(phydev, LAN_EXT_PAGE_ACCESS_CONTROL, page);
+       phy_write(phydev, LAN_EXT_PAGE_ACCESS_ADDRESS_DATA, addr);
+       phy_write(phydev, LAN_EXT_PAGE_ACCESS_CONTROL,
+                 (page | LAN_EXT_PAGE_ACCESS_CTRL_EP_FUNC));
+
+       val = phy_write(phydev, LAN_EXT_PAGE_ACCESS_ADDRESS_DATA, val);
+       if (val) {
+               phydev_err(phydev, "Error: phy_write has returned error %d\n",
+                          val);
+               return val;
+       }
+       return 0;
+}
+
+static int lan8804_config_init(struct phy_device *phydev)
+{
+       int val;
+
+       /* MDI-X setting for swap A,B transmit */
+       val = lanphy_read_page_reg(phydev, 2, LAN8804_ALIGN_SWAP);
+       val &= ~LAN8804_ALIGN_TX_A_B_SWAP_MASK;
+       val |= LAN8804_ALIGN_TX_A_B_SWAP;
+       lanphy_write_page_reg(phydev, 2, LAN8804_ALIGN_SWAP, val);
+
+       /* Make sure that the PHY will not stop generating the clock when the
+        * link partner goes down
+        */
+       lanphy_write_page_reg(phydev, 31, LAN8814_CLOCK_MANAGEMENT, 0x27e);
+       lanphy_read_page_reg(phydev, 1, LAN8814_LINK_QUALITY);
+
+       return 0;
+}
+
 static struct phy_driver ksphy_driver[] = {
 {
        .phy_id         = PHY_ID_KS8737,
@@ -1718,6 +1777,20 @@ static struct phy_driver ksphy_driver[] = {
        .get_stats      = kszphy_get_stats,
        .suspend        = genphy_suspend,
        .resume         = kszphy_resume,
+}, {
+       .phy_id         = PHY_ID_LAN8804,
+       .phy_id_mask    = MICREL_PHY_ID_MASK,
+       .name           = "Microchip LAN966X Gigabit PHY",
+       .config_init    = lan8804_config_init,
+       .driver_data    = &ksz9021_type,
+       .probe          = kszphy_probe,
+       .soft_reset     = genphy_soft_reset,
+       .read_status    = ksz9031_read_status,
+       .get_sset_count = kszphy_get_sset_count,
+       .get_strings    = kszphy_get_strings,
+       .get_stats      = kszphy_get_stats,
+       .suspend        = genphy_suspend,
+       .resume         = kszphy_resume,
 }, {
        .phy_id         = PHY_ID_KSZ9131,
        .phy_id_mask    = MICREL_PHY_ID_MASK,
@@ -1794,6 +1867,7 @@ static struct mdio_device_id __maybe_unused micrel_tbl[] = {
        { PHY_ID_KSZ8873MLL, MICREL_PHY_ID_MASK },
        { PHY_ID_KSZ886X, MICREL_PHY_ID_MASK },
        { PHY_ID_LAN8814, MICREL_PHY_ID_MASK },
+       { PHY_ID_LAN8804, MICREL_PHY_ID_MASK },
        { }
 };
 
index 3d43c60..1f7c33b 100644 (file)
@@ -28,6 +28,7 @@
 #define PHY_ID_KSZ9031         0x00221620
 #define PHY_ID_KSZ9131         0x00221640
 #define PHY_ID_LAN8814         0x00221660
+#define PHY_ID_LAN8804         0x00221670
 
 #define PHY_ID_KSZ886X         0x00221430
 #define PHY_ID_KSZ8863         0x00221435