OSDN Git Service

net: phy: micrel: Adding interrupt support for Link up/Link down in LAN8814 Quad phy
authorDivya Koppera <Divya.Koppera@microchip.com>
Tue, 21 Dec 2021 11:22:17 +0000 (16:52 +0530)
committerJakub Kicinski <kuba@kernel.org>
Wed, 22 Dec 2021 00:57:25 +0000 (16:57 -0800)
This patch add support for Link up or Link down
interrupt support in LAN8814 Quad phy

Signed-off-by: Divya Koppera <Divya.Koppera@microchip.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://lore.kernel.org/r/20211221112217.9502-1-Divya.Koppera@microchip.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/phy/micrel.c

index 44a24b9..c6a97fc 100644 (file)
 #define KSZ8081_LMD_SHORT_INDICATOR            BIT(12)
 #define KSZ8081_LMD_DELTA_TIME_MASK            GENMASK(8, 0)
 
+/* Lan8814 general Interrupt control/status reg in GPHY specific block. */
+#define LAN8814_INTC                           0x18
+#define LAN8814_INTS                           0x1B
+
+#define LAN8814_INT_LINK_DOWN                  BIT(2)
+#define LAN8814_INT_LINK_UP                    BIT(0)
+#define LAN8814_INT_LINK                       (LAN8814_INT_LINK_UP |\
+                                                LAN8814_INT_LINK_DOWN)
+
+#define LAN8814_INTR_CTRL_REG                  0x34
+#define LAN8814_INTR_CTRL_REG_POLARITY         BIT(1)
+#define LAN8814_INTR_CTRL_REG_INTR_ENABLE      BIT(0)
+
 /* PHY Control 1 */
 #define MII_KSZPHY_CTRL_1                      0x1e
 #define KSZ8081_CTRL1_MDIX_STAT                        BIT(4)
@@ -1620,6 +1633,58 @@ static int lan8804_config_init(struct phy_device *phydev)
        return 0;
 }
 
+static irqreturn_t lan8814_handle_interrupt(struct phy_device *phydev)
+{
+       int irq_status;
+
+       irq_status = phy_read(phydev, LAN8814_INTS);
+       if (irq_status < 0)
+               return IRQ_NONE;
+
+       if (!(irq_status & LAN8814_INT_LINK))
+               return IRQ_NONE;
+
+       phy_trigger_machine(phydev);
+
+       return IRQ_HANDLED;
+}
+
+static int lan8814_ack_interrupt(struct phy_device *phydev)
+{
+       /* bit[12..0] int status, which is a read and clear register. */
+       int rc;
+
+       rc = phy_read(phydev, LAN8814_INTS);
+
+       return (rc < 0) ? rc : 0;
+}
+
+static int lan8814_config_intr(struct phy_device *phydev)
+{
+       int err;
+
+       lanphy_write_page_reg(phydev, 4, LAN8814_INTR_CTRL_REG,
+                             LAN8814_INTR_CTRL_REG_POLARITY |
+                             LAN8814_INTR_CTRL_REG_INTR_ENABLE);
+
+       /* enable / disable interrupts */
+       if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
+               err = lan8814_ack_interrupt(phydev);
+               if (err)
+                       return err;
+
+               err =  phy_write(phydev, LAN8814_INTC, LAN8814_INT_LINK);
+       } else {
+               err =  phy_write(phydev, LAN8814_INTC, 0);
+               if (err)
+                       return err;
+
+               err = lan8814_ack_interrupt(phydev);
+       }
+
+       return err;
+}
+
 static struct phy_driver ksphy_driver[] = {
 {
        .phy_id         = PHY_ID_KS8737,
@@ -1802,6 +1867,8 @@ static struct phy_driver ksphy_driver[] = {
        .get_stats      = kszphy_get_stats,
        .suspend        = genphy_suspend,
        .resume         = kszphy_resume,
+       .config_intr    = lan8814_config_intr,
+       .handle_interrupt = lan8814_handle_interrupt,
 }, {
        .phy_id         = PHY_ID_LAN8804,
        .phy_id_mask    = MICREL_PHY_ID_MASK,