ar71xx: sync ethernet driver changes with trunk to fix MDIO issues on ar7240
[openwrt-10.03/.git] / target / linux / ar71xx / files / drivers / net / ag71xx / ag71xx_phy.c
index 4425b740e52bc3e9725c537c0c685305fd048ddd..d70aaf0921fdcb714808a2c08ecdae6e50d91770 100644 (file)
@@ -44,13 +44,13 @@ static void ag71xx_phy_link_adjust(struct net_device *dev)
 
 void ag71xx_phy_start(struct ag71xx *ag)
 {
+       struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
+
        if (ag->phy_dev) {
                phy_start(ag->phy_dev);
        } else {
-               struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
-
-               ag->duplex = pdata->duplex;
-               ag->speed = pdata->speed;
+               if (pdata->has_ar7240_switch)
+                       ag71xx_ar7240_start(ag);
                ag->link = 1;
                ag71xx_link_adjust(ag);
        }
@@ -58,12 +58,14 @@ void ag71xx_phy_start(struct ag71xx *ag)
 
 void ag71xx_phy_stop(struct ag71xx *ag)
 {
+       struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
+
        if (ag->phy_dev) {
                phy_stop(ag->phy_dev);
        } else {
-               ag->duplex = -1;
+               if (pdata->has_ar7240_switch)
+                       ag71xx_ar7240_stop(ag);
                ag->link = 0;
-               ag->speed = 0;
                ag71xx_link_adjust(ag);
        }
 }
@@ -81,12 +83,16 @@ static int ag71xx_phy_connect_fixed(struct ag71xx *ag)
        case SPEED_1000:
                break;
        default:
-               printk(KERN_ERR "%s: invalid speed specified\n",
-                       dev->name);
+               printk(KERN_ERR "%s: invalid speed specified\n", dev->name);
                ret = -EINVAL;
                break;
        }
 
+       printk(KERN_DEBUG "%s: using fixed link parameters\n", dev->name);
+
+       ag->duplex = pdata->duplex;
+       ag->speed = pdata->speed;
+
        return ret;
 }
 
@@ -95,7 +101,6 @@ static int ag71xx_phy_connect_multi(struct ag71xx *ag)
        struct net_device *dev = ag->dev;
        struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
        struct phy_device *phydev = NULL;
-       int phy_count = 0;
        int phy_addr;
        int ret = 0;
 
@@ -113,50 +118,39 @@ static int ag71xx_phy_connect_multi(struct ag71xx *ag)
 
                if (phydev == NULL)
                        phydev = ag->mii_bus->phy_map[phy_addr];
-
-               phy_count++;
        }
 
-       switch (phy_count) {
-       case 0:
+       if (!phydev) {
                printk(KERN_ERR "%s: no PHY found with phy_mask=%08x\n",
                        dev->name, pdata->phy_mask);
-               ret = -ENODEV;
-               break;
-       case 1:
-               ag->phy_dev = phy_connect(dev, dev_name(&phydev->dev),
-                       &ag71xx_phy_link_adjust, 0, pdata->phy_if_mode);
-
-               if (IS_ERR(ag->phy_dev)) {
-                       printk(KERN_ERR "%s: could not connect to PHY at %s\n",
-                               dev->name, dev_name(&phydev->dev));
-                       return PTR_ERR(ag->phy_dev);
-               }
+               return -ENODEV;
+       }
 
-               /* mask with MAC supported features */
-               if (pdata->has_gbit)
-                       phydev->supported &= PHY_GBIT_FEATURES;
-               else
-                       phydev->supported &= PHY_BASIC_FEATURES;
+       ag->phy_dev = phy_connect(dev, dev_name(&phydev->dev),
+                                 &ag71xx_phy_link_adjust, 0,
+                                 pdata->phy_if_mode);
 
-               phydev->advertising = phydev->supported;
+       if (IS_ERR(ag->phy_dev)) {
+               printk(KERN_ERR "%s: could not connect to PHY at %s\n",
+                       dev->name, dev_name(&phydev->dev));
+               return PTR_ERR(ag->phy_dev);
+       }
 
-               printk(KERN_DEBUG "%s: connected to PHY at %s "
-                       "[uid=%08x, driver=%s]\n",
-                       dev->name, dev_name(&phydev->dev),
-                       phydev->phy_id, phydev->drv->name);
+       /* mask with MAC supported features */
+       if (pdata->has_gbit)
+               phydev->supported &= PHY_GBIT_FEATURES;
+       else
+               phydev->supported &= PHY_BASIC_FEATURES;
 
-               ag->link = 0;
-               ag->speed = 0;
-               ag->duplex = -1;
-               break;
+       phydev->advertising = phydev->supported;
 
-       default:
-               printk(KERN_DEBUG "%s: connected to %d PHYs\n",
-                       dev->name, phy_count);
-               ret = ag71xx_phy_connect_fixed(ag);
-               break;
-       }
+       printk(KERN_DEBUG "%s: connected to PHY at %s [uid=%08x, driver=%s]\n",
+               dev->name, dev_name(&phydev->dev),
+               phydev->phy_id, phydev->drv->name);
+
+       ag->link = 0;
+       ag->speed = 0;
+       ag->duplex = -1;
 
        return ret;
 }
@@ -196,7 +190,7 @@ static struct mii_bus *dev_to_mii_bus(struct device *dev)
        return NULL;
 }
 
-int ag71xx_phy_connect(struct ag71xx *ag)
+int __devinit ag71xx_phy_connect(struct ag71xx *ag)
 {
        struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
 
@@ -214,14 +208,21 @@ int ag71xx_phy_connect(struct ag71xx *ag)
                mutex_unlock(&ag->mii_bus->mdio_lock);
        }
 
+       if (pdata->has_ar7240_switch)
+               return ag71xx_ar7240_init(ag);
+
        if (pdata->phy_mask)
                return ag71xx_phy_connect_multi(ag);
 
        return ag71xx_phy_connect_fixed(ag);
 }
 
-void ag71xx_phy_disconnect(struct ag71xx *ag)
+void __devexit ag71xx_phy_disconnect(struct ag71xx *ag)
 {
-       if (ag->phy_dev)
+       struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
+
+       if (pdata->has_ar7240_switch)
+               ag71xx_ar7240_cleanup(ag);
+       else if (ag->phy_dev)
                phy_disconnect(ag->phy_dev);
 }