phylib: Add Vitesse VSC8221 SGMII PHY
authorTrent Piepho <tpiepho@freescale.com>
Tue, 25 Nov 2008 09:00:47 +0000 (01:00 -0800)
committerDavid S. Miller <davem@davemloft.net>
Tue, 25 Nov 2008 09:00:47 +0000 (01:00 -0800)
PHY is mostly compatible with the existing VSC8244 PHY.  The init sequence
is different and the interrupt mask lacks some bits present in the VSC8244.

Rather than making a copy of the existing VSC234x config_intr function and
change one constant, I modify it to select the interrupt mask based on
which driver is calling it.  This lets it be used by both drivers.

Signed-off-by: Trent Piepho <tpiepho@freescale.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/phy/vitesse.c

index 8874497b6bbfa76384c42bdfc4af9903991af497..dd3b2447e85a63936b49e24d2deaffa7e9ac960d 100644 (file)
@@ -34,6 +34,8 @@
 #define MII_VSC8244_IMASK_DUPLEX       0x1000
 #define MII_VSC8244_IMASK_MASK         0xf000
 
+#define MII_VSC8221_IMASK_MASK         0xa000
+
 /* Vitesse Interrupt Status Register */
 #define MII_VSC8244_ISTAT              0x1a
 #define MII_VSC8244_ISTAT_STATUS       0x8000
 #define MII_VSC8244_AUXCONSTAT_GBIT            0x0010
 #define MII_VSC8244_AUXCONSTAT_100             0x0008
 
+#define MII_VSC8221_AUXCONSTAT_INIT    0x0004 /* need to set this bit? */
+#define MII_VSC8221_AUXCONSTAT_RESERVED        0x0004
+
+#define PHY_ID_VSC8244                 0x000fc6c0
+#define PHY_ID_VSC8221                 0x000fc550
+
 MODULE_DESCRIPTION("Vitesse PHY driver");
 MODULE_AUTHOR("Kriston Carson");
 MODULE_LICENSE("GPL");
@@ -95,13 +103,15 @@ static int vsc824x_ack_interrupt(struct phy_device *phydev)
        return (err < 0) ? err : 0;
 }
 
-static int vsc824x_config_intr(struct phy_device *phydev)
+static int vsc82xx_config_intr(struct phy_device *phydev)
 {
        int err;
 
        if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
                err = phy_write(phydev, MII_VSC8244_IMASK,
-                               MII_VSC8244_IMASK_MASK);
+                       phydev->drv->phy_id == PHY_ID_VSC8244 ?
+                               MII_VSC8244_IMASK_MASK :
+                               MII_VSC8221_IMASK_MASK);
        else {
                /*
                 * The Vitesse PHY cannot clear the interrupt
@@ -120,7 +130,7 @@ static int vsc824x_config_intr(struct phy_device *phydev)
 
 /* Vitesse 824x */
 static struct phy_driver vsc8244_driver = {
-       .phy_id         = 0x000fc6c0,
+       .phy_id         = PHY_ID_VSC8244,
        .name           = "Vitesse VSC8244",
        .phy_id_mask    = 0x000fffc0,
        .features       = PHY_GBIT_FEATURES,
@@ -129,19 +139,55 @@ static struct phy_driver vsc8244_driver = {
        .config_aneg    = &genphy_config_aneg,
        .read_status    = &genphy_read_status,
        .ack_interrupt  = &vsc824x_ack_interrupt,
-       .config_intr    = &vsc824x_config_intr,
+       .config_intr    = &vsc82xx_config_intr,
        .driver         = { .owner = THIS_MODULE,},
 };
 
-static int __init vsc8244_init(void)
+static int vsc8221_config_init(struct phy_device *phydev)
 {
-       return phy_driver_register(&vsc8244_driver);
+       int err;
+
+       err = phy_write(phydev, MII_VSC8244_AUX_CONSTAT,
+                       MII_VSC8221_AUXCONSTAT_INIT);
+       return err;
+
+       /* Perhaps we should set EXT_CON1 based on the interface?
+          Options are 802.3Z SerDes or SGMII */
+}
+
+/* Vitesse 8221 */
+static struct phy_driver vsc8221_driver = {
+       .phy_id         = PHY_ID_VSC8221,
+       .phy_id_mask    = 0x000ffff0,
+       .name           = "Vitesse VSC8221",
+       .features       = PHY_GBIT_FEATURES,
+       .flags          = PHY_HAS_INTERRUPT,
+       .config_init    = &vsc8221_config_init,
+       .config_aneg    = &genphy_config_aneg,
+       .read_status    = &genphy_read_status,
+       .ack_interrupt  = &vsc824x_ack_interrupt,
+       .config_intr    = &vsc82xx_config_intr,
+       .driver         = { .owner = THIS_MODULE,},
+};
+
+static int __init vsc82xx_init(void)
+{
+       int err;
+
+       err = phy_driver_register(&vsc8244_driver);
+       if (err < 0)
+               return err;
+       err = phy_driver_register(&vsc8221_driver);
+       if (err < 0)
+               phy_driver_unregister(&vsc8244_driver);
+       return err;
 }
 
-static void __exit vsc8244_exit(void)
+static void __exit vsc82xx_exit(void)
 {
        phy_driver_unregister(&vsc8244_driver);
+       phy_driver_unregister(&vsc8221_driver);
 }
 
-module_init(vsc8244_init);
-module_exit(vsc8244_exit);
+module_init(vsc82xx_init);
+module_exit(vsc82xx_exit);