ath79: ag71xx: Split mdio driver into an independent platform device.
authorChuanhong Guo <gch981213@gmail.com>
Tue, 17 Jul 2018 09:09:13 +0000 (17:09 +0800)
committerJohn Crispin <john@phrozen.org>
Mon, 30 Jul 2018 08:43:33 +0000 (10:43 +0200)
We need to have mdio1 belonging to gmac1 initialized before gmac0.
Split it into a separated mdio device to get both mdios ready before probing gmac.

Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/Makefile
target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx.h
target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c
target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_mdio.c

index ed74e3b5e602d0f1bd1930714d07854cb3405062..3636077166dfb1eb093cd10216d6c4206929ca2e 100644 (file)
@@ -6,10 +6,10 @@ ag71xx-y      += ag71xx_main.o
 ag71xx-y       += ag71xx_gmac.o
 ag71xx-y       += ag71xx_ethtool.o
 ag71xx-y       += ag71xx_phy.o
-ag71xx-y       += ag71xx_mdio.o
 ag71xx-y       += ag71xx_ar7240.o
 
 ag71xx-$(CONFIG_AG71XX_DEBUG_FS)       += ag71xx_debugfs.o
 
+obj-$(CONFIG_AG71XX)   += ag71xx_mdio.o
 obj-$(CONFIG_AG71XX)   += ag71xx.o
 
index d154bbec9e7a44523e5943e0a5fd63018fb07ae9..70c85822942a36427ae4b4cfc726b782f22f8629 100644 (file)
@@ -170,12 +170,10 @@ struct ag71xx {
         */
        void __iomem            *mac_base;
        void __iomem            *mii_base;
-       struct regmap           *mii_regmap;
 
        struct ag71xx_desc      *stop_desc;
        dma_addr_t              stop_desc_dma;
 
-       struct mii_bus          *mii_bus;
        struct phy_device       *phy_dev;
        void                    *phy_priv;
        int                     phy_if_mode;
@@ -189,7 +187,6 @@ struct ag71xx {
 
        struct reset_control *mac_reset;
        struct reset_control *phy_reset;
-       struct reset_control *mdio_reset;
 
        u32                     fifodata[3];
        u32                     plldata[3];
@@ -201,6 +198,12 @@ struct ag71xx {
 #endif
 };
 
+struct ag71xx_mdio {
+       struct reset_control *mdio_reset;
+       struct mii_bus          *mii_bus;
+       struct regmap           *mii_regmap;
+};
+
 extern struct ethtool_ops ag71xx_ethtool_ops;
 void ag71xx_link_adjust(struct ag71xx *ag);
 
@@ -441,11 +444,6 @@ static inline void ag71xx_debugfs_update_napi_stats(struct ag71xx *ag,
 int ag71xx_ar7240_init(struct ag71xx *ag, struct device_node *np);
 void ag71xx_ar7240_cleanup(struct ag71xx *ag);
 
-int ag71xx_mdio_init(struct ag71xx *ag);
-void ag71xx_mdio_cleanup(struct ag71xx *ag);
-int ag71xx_mdio_mii_read(struct mii_bus *bus, int addr, int reg);
-int ag71xx_mdio_mii_write(struct mii_bus *bus, int addr, int reg, u16 val);
-
 int ag71xx_setup_gmac(struct device_node *np);
 
 int ar7240sw_phy_read(struct mii_bus *mii, int addr, int reg);
index 72cfd6cf1516ec3ad6df0c26ca387d164d4efc7d..e741bdfa7b60f523613dd82643ee4841379df071 100644 (file)
@@ -1438,11 +1438,10 @@ static int ag71xx_probe(struct platform_device *pdev)
 
        ag71xx_wr(ag, AG71XX_REG_MAC_CFG1, 0);
        ag71xx_hw_init(ag);
-       ag71xx_mdio_init(ag);
 
        err = ag71xx_phy_connect(ag);
        if (err)
-               goto err_mdio_free;
+               goto err_free;
 
        err = ag71xx_debugfs_init(ag);
        if (err)
@@ -1466,8 +1465,6 @@ static int ag71xx_probe(struct platform_device *pdev)
 
 err_phy_disconnect:
        ag71xx_phy_disconnect(ag);
-err_mdio_free:
-       ag71xx_mdio_cleanup(ag);
 err_free:
        free_netdev(dev);
        return err;
@@ -1484,7 +1481,6 @@ static int ag71xx_remove(struct platform_device *pdev)
        ag = netdev_priv(dev);
        ag71xx_debugfs_exit(ag);
        ag71xx_phy_disconnect(ag);
-       ag71xx_mdio_cleanup(ag);
        unregister_netdev(dev);
        free_irq(dev->irq, dev);
        iounmap(ag->mac_base);
index 8c1572b1814d2c76def11639567cd538c1eaf27b..baaa33e10be2a4dd19e5e321ff88136f98f50fb6 100644 (file)
@@ -20,7 +20,7 @@
 
 static int bus_count;
 
-static int ag71xx_mdio_wait_busy(struct ag71xx *ag)
+static int ag71xx_mdio_wait_busy(struct ag71xx_mdio *am)
 {
        int i;
 
@@ -29,57 +29,57 @@ static int ag71xx_mdio_wait_busy(struct ag71xx *ag)
 
                udelay(AG71XX_MDIO_DELAY);
 
-               regmap_read(ag->mii_regmap, AG71XX_REG_MII_IND, &busy);
+               regmap_read(am->mii_regmap, AG71XX_REG_MII_IND, &busy);
                if (!busy)
                        return 0;
 
                udelay(AG71XX_MDIO_DELAY);
        }
 
-       pr_err("%s: MDIO operation timed out\n", ag->mii_bus->name);
+       pr_err("%s: MDIO operation timed out\n", am->mii_bus->name);
 
        return -ETIMEDOUT;
 }
 
-int ag71xx_mdio_mii_read(struct mii_bus *bus, int addr, int reg)
+static int ag71xx_mdio_mii_read(struct mii_bus *bus, int addr, int reg)
 {
-       struct ag71xx *ag = bus->priv;
+       struct ag71xx_mdio *am = bus->priv;
        int err;
        int ret;
 
-       err = ag71xx_mdio_wait_busy(ag);
+       err = ag71xx_mdio_wait_busy(am);
        if (err)
                return 0xffff;
 
-       regmap_write(ag->mii_regmap, AG71XX_REG_MII_CMD, MII_CMD_WRITE);
-       regmap_write(ag->mii_regmap, AG71XX_REG_MII_ADDR,
+       regmap_write(am->mii_regmap, AG71XX_REG_MII_CMD, MII_CMD_WRITE);
+       regmap_write(am->mii_regmap, AG71XX_REG_MII_ADDR,
                        ((addr & 0xff) << MII_ADDR_SHIFT) | (reg & 0xff));
-       regmap_write(ag->mii_regmap, AG71XX_REG_MII_CMD, MII_CMD_READ);
+       regmap_write(am->mii_regmap, AG71XX_REG_MII_CMD, MII_CMD_READ);
 
-       err = ag71xx_mdio_wait_busy(ag);
+       err = ag71xx_mdio_wait_busy(am);
        if (err)
                return 0xffff;
 
-       regmap_read(ag->mii_regmap, AG71XX_REG_MII_STATUS, &ret);
+       regmap_read(am->mii_regmap, AG71XX_REG_MII_STATUS, &ret);
        ret &= 0xffff;
-       regmap_write(ag->mii_regmap, AG71XX_REG_MII_CMD, MII_CMD_WRITE);
+       regmap_write(am->mii_regmap, AG71XX_REG_MII_CMD, MII_CMD_WRITE);
 
        DBG("mii_read: addr=%04x, reg=%04x, value=%04x\n", addr, reg, ret);
 
        return ret;
 }
 
-int ag71xx_mdio_mii_write(struct mii_bus *bus, int addr, int reg, u16 val)
+static int ag71xx_mdio_mii_write(struct mii_bus *bus, int addr, int reg, u16 val)
 {
-       struct ag71xx *ag = bus->priv;
+       struct ag71xx_mdio *am = bus->priv;
 
        DBG("mii_write: addr=%04x, reg=%04x, value=%04x\n", addr, reg, val);
 
-       regmap_write(ag->mii_regmap, AG71XX_REG_MII_ADDR,
+       regmap_write(am->mii_regmap, AG71XX_REG_MII_ADDR,
                        ((addr & 0xff) << MII_ADDR_SHIFT) | (reg & 0xff));
-       regmap_write(ag->mii_regmap, AG71XX_REG_MII_CTRL, val);
+       regmap_write(am->mii_regmap, AG71XX_REG_MII_CTRL, val);
 
-       ag71xx_mdio_wait_busy(ag);
+       ag71xx_mdio_wait_busy(am);
 
        return 0;
 }
@@ -97,23 +97,22 @@ static int ar934x_mdio_clock_div(unsigned int rate)
 static int ag71xx_mdio_reset(struct mii_bus *bus)
 {
        struct device_node *np = bus->dev.of_node;
-       struct ag71xx *ag = bus->priv;
-       struct device_node *np_ag = ag->pdev->dev.of_node;
+       struct ag71xx_mdio *am = bus->priv;
        bool builtin_switch;
        u32 t;
 
        builtin_switch = of_property_read_bool(np, "builtin-switch");
 
-       if (of_device_is_compatible(np_ag, "qca,ar7240-eth"))
+       if (of_device_is_compatible(np, "qca,ar7240-mdio"))
                t = MII_CFG_CLK_DIV_6;
-       else if (of_device_is_compatible(np_ag, "qca,ar9340-eth"))
+       else if (of_device_is_compatible(np, "qca,ar9340-mdio"))
                t = MII_CFG_CLK_DIV_58;
        else if (builtin_switch)
                t = MII_CFG_CLK_DIV_10;
        else
                t = MII_CFG_CLK_DIV_28;
 
-       if (builtin_switch && of_device_is_compatible(np_ag, "qca,ar9340-eth")) {
+       if (builtin_switch && of_device_is_compatible(np, "qca,ar9340-mdio")) {
                struct clk *ref_clk = of_clk_get(np, 0);
                int clock_rate;
 
@@ -126,56 +125,45 @@ static int ag71xx_mdio_reset(struct mii_bus *bus)
                clk_put(ref_clk);
        }
 
-       regmap_write(ag->mii_regmap, AG71XX_REG_MII_CFG, t | MII_CFG_RESET);
+       regmap_write(am->mii_regmap, AG71XX_REG_MII_CFG, t | MII_CFG_RESET);
        udelay(100);
 
-       regmap_write(ag->mii_regmap, AG71XX_REG_MII_CFG, t);
+       regmap_write(am->mii_regmap, AG71XX_REG_MII_CFG, t);
        udelay(100);
 
        return 0;
 }
 
-int ag71xx_mdio_init(struct ag71xx *ag)
+static int ag71xx_mdio_probe(struct platform_device *pdev)
 {
-       struct device *parent = &ag->pdev->dev;
-       struct device_node *np;
+       struct device *amdev = &pdev->dev;
+       struct device_node *np = pdev->dev.of_node;
+       struct ag71xx_mdio *am;
        struct mii_bus *mii_bus;
        bool builtin_switch;
        int i, err;
 
-       np = of_get_child_by_name(parent->of_node, "mdio-bus");
-       if (!np)
-               return -ENODEV;
+       am = devm_kzalloc(amdev, sizeof(*am), GFP_KERNEL);
+       if (!am)
+               return -ENOMEM;
 
-       if (!of_device_is_available(np)) {
-               err = 0;
-               goto err_out;
-       }
-
-       ag->mii_regmap = syscon_regmap_lookup_by_phandle(np, "regmap");
-       if (!ag->mii_regmap)
+       am->mii_regmap = syscon_regmap_lookup_by_phandle(np, "regmap");
+       if (!am->mii_regmap)
                return -ENOENT;
 
-       mii_bus = devm_mdiobus_alloc(parent);
-       if (!mii_bus) {
-               err = -ENOMEM;
-               goto err_out;
-       }
+       mii_bus = devm_mdiobus_alloc(amdev);
+       if (!mii_bus)
+               return -ENOMEM;
 
-       ag->mdio_reset = of_reset_control_get_exclusive(np, "mdio");
+       am->mdio_reset = of_reset_control_get_exclusive(np, "mdio");
        builtin_switch = of_property_read_bool(np, "builtin-switch");
 
-       mii_bus->name = "mdio";
-       if (builtin_switch) {
-               mii_bus->read = ar7240sw_phy_read;
-               mii_bus->write = ar7240sw_phy_write;
-       } else {
-               mii_bus->read = ag71xx_mdio_mii_read;
-               mii_bus->write = ag71xx_mdio_mii_write;
-       }
+       mii_bus->name = "ag71xx_mdio";
+       mii_bus->read = ag71xx_mdio_mii_read;
+       mii_bus->write = ag71xx_mdio_mii_write;
        mii_bus->reset = ag71xx_mdio_reset;
-       mii_bus->priv = ag;
-       mii_bus->parent = parent;
+       mii_bus->priv = am;
+       mii_bus->parent = amdev;
        snprintf(mii_bus->id, MII_BUS_ID_SIZE, "%s.%d", np->name, bus_count++);
 
        if (!builtin_switch &&
@@ -185,34 +173,46 @@ int ag71xx_mdio_init(struct ag71xx *ag)
        for (i = 0; i < PHY_MAX_ADDR; i++)
                mii_bus->irq[i] = PHY_POLL;
 
-       if (!IS_ERR(ag->mdio_reset)) {
-               reset_control_assert(ag->mdio_reset);
+       if (!IS_ERR(am->mdio_reset)) {
+               reset_control_assert(am->mdio_reset);
                msleep(100);
-               reset_control_deassert(ag->mdio_reset);
+               reset_control_deassert(am->mdio_reset);
                msleep(200);
        }
 
        err = of_mdiobus_register(mii_bus, np);
        if (err)
-               goto err_out;
-
-       ag->mii_bus = mii_bus;
+               return err;
 
-       if (builtin_switch)
-               ag71xx_ar7240_init(ag, np);
+       am->mii_bus = mii_bus;
+       platform_set_drvdata(pdev, am);
 
        return 0;
-
-err_out:
-       of_node_put(np);
-       return err;
 }
 
-void ag71xx_mdio_cleanup(struct ag71xx *ag)
+static int ag71xx_mdio_remove(struct platform_device *pdev)
 {
-       if (!ag->mii_bus)
-               return;
+       struct ag71xx_mdio *am = platform_get_drvdata(pdev);
 
-       ag71xx_ar7240_cleanup(ag);
-       mdiobus_unregister(ag->mii_bus);
+       mdiobus_unregister(am->mii_bus);
+       return 0;
 }
+
+static const struct of_device_id ag71xx_mdio_match[] = {
+       { .compatible = "qca,ar7240-mdio" },
+       { .compatible = "qca,ar9340-mdio" },
+       { .compatible = "qca,ath79-mdio" },
+       {}
+};
+
+static struct platform_driver ag71xx_mdio_driver = {
+       .probe          = ag71xx_mdio_probe,
+       .remove         = ag71xx_mdio_remove,
+       .driver = {
+               .name    = "ag71xx-mdio",
+               .of_match_table = ag71xx_mdio_match,
+       }
+};
+
+module_platform_driver(ag71xx_mdio_driver);
+MODULE_LICENSE("GPL");