net/phy: Add interrupt support for dp83640 phy.
authorStephan Gatzka <stephan.gatzka@gmail.com>
Tue, 4 Dec 2012 10:21:38 +0000 (10:21 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 5 Dec 2012 21:01:28 +0000 (16:01 -0500)
Added functions for ack_interrupt and config_intr. Tested on an mpc5200b
powerpc board.

Signed-off-by: Stephan Gatzka <stephan.gatzka@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/phy/dp83640.c

index 24e05c4..7490b6c 100644 (file)
 #define CAL_TRIGGER    7
 #define PER_TRIGGER    6
 
+#define MII_DP83640_MICR 0x11
+#define MII_DP83640_MISR 0x12
+
+#define MII_DP83640_MICR_OE 0x1
+#define MII_DP83640_MICR_IE 0x2
+
+#define MII_DP83640_MISR_RHF_INT_EN 0x01
+#define MII_DP83640_MISR_FHF_INT_EN 0x02
+#define MII_DP83640_MISR_ANC_INT_EN 0x04
+#define MII_DP83640_MISR_DUP_INT_EN 0x08
+#define MII_DP83640_MISR_SPD_INT_EN 0x10
+#define MII_DP83640_MISR_LINK_INT_EN 0x20
+#define MII_DP83640_MISR_ED_INT_EN 0x40
+#define MII_DP83640_MISR_LQ_INT_EN 0x80
+
 /* phyter seems to miss the mark by 16 ns */
 #define ADJTIME_FIX    16
 
@@ -1043,6 +1058,65 @@ static void dp83640_remove(struct phy_device *phydev)
        kfree(dp83640);
 }
 
+static int dp83640_ack_interrupt(struct phy_device *phydev)
+{
+       int err = phy_read(phydev, MII_DP83640_MISR);
+
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+static int dp83640_config_intr(struct phy_device *phydev)
+{
+       int micr;
+       int misr;
+       int err;
+
+       if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
+               misr = phy_read(phydev, MII_DP83640_MISR);
+               if (misr < 0)
+                       return misr;
+               misr |=
+                       (MII_DP83640_MISR_ANC_INT_EN |
+                       MII_DP83640_MISR_DUP_INT_EN |
+                       MII_DP83640_MISR_SPD_INT_EN |
+                       MII_DP83640_MISR_LINK_INT_EN);
+               err = phy_write(phydev, MII_DP83640_MISR, misr);
+               if (err < 0)
+                       return err;
+
+               micr = phy_read(phydev, MII_DP83640_MICR);
+               if (micr < 0)
+                       return micr;
+               micr |=
+                       (MII_DP83640_MICR_OE |
+                       MII_DP83640_MICR_IE);
+               return phy_write(phydev, MII_DP83640_MICR, micr);
+       } else {
+               micr = phy_read(phydev, MII_DP83640_MICR);
+               if (micr < 0)
+                       return micr;
+               micr &=
+                       ~(MII_DP83640_MICR_OE |
+                       MII_DP83640_MICR_IE);
+               err = phy_write(phydev, MII_DP83640_MICR, micr);
+               if (err < 0)
+                       return err;
+
+               misr = phy_read(phydev, MII_DP83640_MISR);
+               if (misr < 0)
+                       return misr;
+               misr &=
+                       ~(MII_DP83640_MISR_ANC_INT_EN |
+                       MII_DP83640_MISR_DUP_INT_EN |
+                       MII_DP83640_MISR_SPD_INT_EN |
+                       MII_DP83640_MISR_LINK_INT_EN);
+               return phy_write(phydev, MII_DP83640_MISR, misr);
+       }
+}
+
 static int dp83640_hwtstamp(struct phy_device *phydev, struct ifreq *ifr)
 {
        struct dp83640_private *dp83640 = phydev->priv;
@@ -1253,11 +1327,13 @@ static struct phy_driver dp83640_driver = {
        .phy_id_mask    = 0xfffffff0,
        .name           = "NatSemi DP83640",
        .features       = PHY_BASIC_FEATURES,
-       .flags          = 0,
+       .flags          = PHY_HAS_INTERRUPT,
        .probe          = dp83640_probe,
        .remove         = dp83640_remove,
        .config_aneg    = genphy_config_aneg,
        .read_status    = genphy_read_status,
+       .ack_interrupt  = dp83640_ack_interrupt,
+       .config_intr    = dp83640_config_intr,
        .ts_info        = dp83640_ts_info,
        .hwtstamp       = dp83640_hwtstamp,
        .rxtstamp       = dp83640_rxtstamp,