diff options
-rw-r--r-- | drivers/net/phy/microchip.c | 46 |
1 files changed, 43 insertions, 3 deletions
diff --git a/drivers/net/phy/microchip.c b/drivers/net/phy/microchip.c index 7c8bcec0a8fa..230f2fcf9c46 100644 --- a/drivers/net/phy/microchip.c +++ b/drivers/net/phy/microchip.c @@ -31,6 +31,47 @@ static int lan88xx_write_page(struct phy_device *phydev, int page) return __phy_write(phydev, LAN88XX_EXT_PAGE_ACCESS, page); } +static int lan88xx_phy_config_intr(struct phy_device *phydev) +{ + int rc; + + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { + /* unmask all source and clear them before enable */ + rc = phy_write(phydev, LAN88XX_INT_MASK, 0x7FFF); + rc = phy_read(phydev, LAN88XX_INT_STS); + rc = phy_write(phydev, LAN88XX_INT_MASK, + LAN88XX_INT_MASK_MDINTPIN_EN_ | + LAN88XX_INT_MASK_LINK_CHANGE_); + } else { + rc = phy_write(phydev, LAN88XX_INT_MASK, 0); + if (rc) + return rc; + + /* Ack interrupts after they have been disabled */ + rc = phy_read(phydev, LAN88XX_INT_STS); + } + + return rc < 0 ? rc : 0; +} + +static irqreturn_t lan88xx_handle_interrupt(struct phy_device *phydev) +{ + int irq_status; + + irq_status = phy_read(phydev, LAN88XX_INT_STS); + if (irq_status < 0) { + phy_error(phydev); + return IRQ_NONE; + } + + if (!(irq_status & LAN88XX_INT_STS_LINK_CHANGE_)) + return IRQ_NONE; + + phy_trigger_machine(phydev); + + return IRQ_HANDLED; +} + static int lan88xx_suspend(struct phy_device *phydev) { struct lan88xx_priv *priv = phydev->priv; @@ -347,9 +388,8 @@ static struct phy_driver microchip_phy_driver[] = { .config_aneg = lan88xx_config_aneg, .link_change_notify = lan88xx_link_change_notify, - /* Interrupt handling is broken, do not define related - * functions to force polling. - */ + .config_intr = lan88xx_phy_config_intr, + .handle_interrupt = lan88xx_handle_interrupt, .suspend = lan88xx_suspend, .resume = genphy_resume, |