These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / net / ethernet / ti / cpsw.c
index b536b4c..fc95806 100644 (file)
@@ -29,7 +29,9 @@
 #include <linux/workqueue.h>
 #include <linux/delay.h>
 #include <linux/pm_runtime.h>
+#include <linux/gpio.h>
 #include <linux/of.h>
+#include <linux/of_mdio.h>
 #include <linux/of_net.h>
 #include <linux/of_device.h>
 #include <linux/if_vlan.h>
@@ -138,19 +140,6 @@ do {                                                               \
 #define CPSW_CMINTMAX_INTVL    (1000 / CPSW_CMINTMIN_CNT)
 #define CPSW_CMINTMIN_INTVL    ((1000 / CPSW_CMINTMAX_CNT) + 1)
 
-#define cpsw_enable_irq(priv)  \
-       do {                    \
-               u32 i;          \
-               for (i = 0; i < priv->num_irqs; i++) \
-                       enable_irq(priv->irqs_table[i]); \
-       } while (0)
-#define cpsw_disable_irq(priv) \
-       do {                    \
-               u32 i;          \
-               for (i = 0; i < priv->num_irqs; i++) \
-                       disable_irq_nosync(priv->irqs_table[i]); \
-       } while (0)
-
 #define cpsw_slave_index(priv)                         \
                ((priv->data.dual_emac) ? priv->emac_port :     \
                priv->data.active_slave)
@@ -378,7 +367,9 @@ struct cpsw_priv {
        spinlock_t                      lock;
        struct platform_device          *pdev;
        struct net_device               *ndev;
-       struct napi_struct              napi;
+       struct device_node              *phy_node;
+       struct napi_struct              napi_rx;
+       struct napi_struct              napi_tx;
        struct device                   *dev;
        struct cpsw_platform_data       data;
        struct cpsw_ss_regs __iomem     *regs;
@@ -399,10 +390,12 @@ struct cpsw_priv {
        struct cpsw_ale                 *ale;
        bool                            rx_pause;
        bool                            tx_pause;
+       bool                            quirk_irq;
+       bool                            rx_irq_disabled;
+       bool                            tx_irq_disabled;
        /* snapshot of IRQ numbers */
        u32 irqs_table[4];
        u32 num_irqs;
-       bool irq_enabled;
        struct cpts *cpts;
        u32 emac_port;
 };
@@ -509,9 +502,11 @@ static const struct cpsw_stats cpsw_gstrings_stats[] = {
                                (func)(slave++, ##arg);                 \
        } while (0)
 #define cpsw_get_slave_ndev(priv, __slave_no__)                                \
-       (priv->slaves[__slave_no__].ndev)
+       ((__slave_no__ < priv->data.slaves) ?                           \
+               priv->slaves[__slave_no__].ndev : NULL)
 #define cpsw_get_slave_priv(priv, __slave_no__)                                \
-       ((priv->slaves[__slave_no__].ndev) ?                            \
+       (((__slave_no__ < priv->data.slaves) &&                         \
+               (priv->slaves[__slave_no__].ndev)) ?                    \
                netdev_priv(priv->slaves[__slave_no__].ndev) : NULL)    \
 
 #define cpsw_dual_emac_src_port_detect(status, priv, ndev, skb)                \
@@ -763,13 +758,15 @@ static irqreturn_t cpsw_tx_interrupt(int irq, void *dev_id)
 {
        struct cpsw_priv *priv = dev_id;
 
+       writel(0, &priv->wr_regs->tx_en);
        cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX);
-       cpdma_chan_process(priv->txch, 128);
 
-       priv = cpsw_get_slave_priv(priv, 1);
-       if (priv)
-               cpdma_chan_process(priv->txch, 128);
+       if (priv->quirk_irq) {
+               disable_irq_nosync(priv->irqs_table[1]);
+               priv->tx_irq_disabled = true;
+       }
 
+       napi_schedule(&priv->napi_tx);
        return IRQ_HANDLED;
 }
 
@@ -778,52 +775,55 @@ static irqreturn_t cpsw_rx_interrupt(int irq, void *dev_id)
        struct cpsw_priv *priv = dev_id;
 
        cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX);
+       writel(0, &priv->wr_regs->rx_en);
 
-       cpsw_intr_disable(priv);
-       if (priv->irq_enabled == true) {
-               cpsw_disable_irq(priv);
-               priv->irq_enabled = false;
+       if (priv->quirk_irq) {
+               disable_irq_nosync(priv->irqs_table[0]);
+               priv->rx_irq_disabled = true;
        }
 
-       if (netif_running(priv->ndev)) {
-               napi_schedule(&priv->napi);
-               return IRQ_HANDLED;
-       }
+       napi_schedule(&priv->napi_rx);
+       return IRQ_HANDLED;
+}
 
-       priv = cpsw_get_slave_priv(priv, 1);
-       if (!priv)
-               return IRQ_NONE;
+static int cpsw_tx_poll(struct napi_struct *napi_tx, int budget)
+{
+       struct cpsw_priv        *priv = napi_to_priv(napi_tx);
+       int                     num_tx;
 
-       if (netif_running(priv->ndev)) {
-               napi_schedule(&priv->napi);
-               return IRQ_HANDLED;
+       num_tx = cpdma_chan_process(priv->txch, budget);
+       if (num_tx < budget) {
+               napi_complete(napi_tx);
+               writel(0xff, &priv->wr_regs->tx_en);
+               if (priv->quirk_irq && priv->tx_irq_disabled) {
+                       priv->tx_irq_disabled = false;
+                       enable_irq(priv->irqs_table[1]);
+               }
        }
-       return IRQ_NONE;
+
+       if (num_tx)
+               cpsw_dbg(priv, intr, "poll %d tx pkts\n", num_tx);
+
+       return num_tx;
 }
 
-static int cpsw_poll(struct napi_struct *napi, int budget)
+static int cpsw_rx_poll(struct napi_struct *napi_rx, int budget)
 {
-       struct cpsw_priv        *priv = napi_to_priv(napi);
-       int                     num_tx, num_rx;
-
-       num_tx = cpdma_chan_process(priv->txch, 128);
+       struct cpsw_priv        *priv = napi_to_priv(napi_rx);
+       int                     num_rx;
 
        num_rx = cpdma_chan_process(priv->rxch, budget);
        if (num_rx < budget) {
-               struct cpsw_priv *prim_cpsw;
-
-               napi_complete(napi);
-               cpsw_intr_enable(priv);
-               prim_cpsw = cpsw_get_slave_priv(priv, 0);
-               if (prim_cpsw->irq_enabled == false) {
-                       prim_cpsw->irq_enabled = true;
-                       cpsw_enable_irq(priv);
+               napi_complete(napi_rx);
+               writel(0xff, &priv->wr_regs->rx_en);
+               if (priv->quirk_irq && priv->rx_irq_disabled) {
+                       priv->rx_irq_disabled = false;
+                       enable_irq(priv->irqs_table[0]);
                }
        }
 
-       if (num_rx || num_tx)
-               cpsw_dbg(priv, intr, "poll %d rx, %d tx pkts\n",
-                        num_rx, num_tx);
+       if (num_rx)
+               cpsw_dbg(priv, intr, "poll %d rx pkts\n", num_rx);
 
        return num_rx;
 }
@@ -1148,7 +1148,11 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv)
                cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast,
                                   1 << slave_port, 0, 0, ALE_MCAST_FWD_2);
 
-       slave->phy = phy_connect(priv->ndev, slave->data->phy_id,
+       if (priv->phy_node)
+               slave->phy = of_phy_connect(priv->ndev, priv->phy_node,
+                                &cpsw_adjust_link, 0, slave->data->phy_if);
+       else
+               slave->phy = phy_connect(priv->ndev, slave->data->phy_id,
                                 &cpsw_adjust_link, slave->data->phy_if);
        if (IS_ERR(slave->phy)) {
                dev_err(priv->dev, "phy %s not found on slave %d\n",
@@ -1244,7 +1248,6 @@ static void cpsw_slave_stop(struct cpsw_slave *slave, struct cpsw_priv *priv)
 static int cpsw_ndo_open(struct net_device *ndev)
 {
        struct cpsw_priv *priv = netdev_priv(ndev);
-       struct cpsw_priv *prim_cpsw;
        int i, ret;
        u32 reg;
 
@@ -1274,6 +1277,8 @@ static int cpsw_ndo_open(struct net_device *ndev)
                                  ALE_ALL_PORTS << priv->host_port, 0, 0);
 
        if (!cpsw_common_res_usage_state(priv)) {
+               struct cpsw_priv *priv_sl0 = cpsw_get_slave_priv(priv, 0);
+
                /* setup tx dma to fixed prio and zero offset */
                cpdma_control_set(priv->dma, CPDMA_TX_PRIO_FIXED, 1);
                cpdma_control_set(priv->dma, CPDMA_RX_BUFFER_OFFSET, 0);
@@ -1287,6 +1292,19 @@ static int cpsw_ndo_open(struct net_device *ndev)
                /* Enable internal fifo flow control */
                writel(0x7, &priv->regs->flow_control);
 
+               napi_enable(&priv_sl0->napi_rx);
+               napi_enable(&priv_sl0->napi_tx);
+
+               if (priv_sl0->tx_irq_disabled) {
+                       priv_sl0->tx_irq_disabled = false;
+                       enable_irq(priv->irqs_table[1]);
+               }
+
+               if (priv_sl0->rx_irq_disabled) {
+                       priv_sl0->rx_irq_disabled = false;
+                       enable_irq(priv->irqs_table[0]);
+               }
+
                if (WARN_ON(!priv->data.rx_descs))
                        priv->data.rx_descs = 128;
 
@@ -1325,18 +1343,9 @@ static int cpsw_ndo_open(struct net_device *ndev)
                cpsw_set_coalesce(ndev, &coal);
        }
 
-       napi_enable(&priv->napi);
        cpdma_ctlr_start(priv->dma);
        cpsw_intr_enable(priv);
 
-       prim_cpsw = cpsw_get_slave_priv(priv, 0);
-       if (prim_cpsw->irq_enabled == false) {
-               if ((priv == prim_cpsw) || !netif_running(prim_cpsw->ndev)) {
-                       prim_cpsw->irq_enabled = true;
-                       cpsw_enable_irq(prim_cpsw);
-               }
-       }
-
        if (priv->data.dual_emac)
                priv->slaves[priv->emac_port].open_stat = true;
        return 0;
@@ -1355,13 +1364,15 @@ static int cpsw_ndo_stop(struct net_device *ndev)
 
        cpsw_info(priv, ifdown, "shutting down cpsw device\n");
        netif_stop_queue(priv->ndev);
-       napi_disable(&priv->napi);
        netif_carrier_off(priv->ndev);
 
        if (cpsw_common_res_usage_state(priv) <= 1) {
+               struct cpsw_priv *priv_sl0 = cpsw_get_slave_priv(priv, 0);
+
+               napi_disable(&priv_sl0->napi_rx);
+               napi_disable(&priv_sl0->napi_tx);
                cpts_unregister(priv->cpts);
                cpsw_intr_disable(priv);
-               cpdma_ctlr_int_ctrl(priv->dma, false);
                cpdma_ctlr_stop(priv->dma);
                cpsw_ale_stop(priv->ale);
        }
@@ -1456,7 +1467,7 @@ static void cpsw_hwtstamp_v2(struct cpsw_priv *priv)
 
                if (priv->cpts->rx_enable)
                        ctrl |= CTRL_V2_RX_TS_BITS;
-       break;
+               break;
        case CPSW_VERSION_3:
        default:
                ctrl &= ~CTRL_V3_ALL_TS_MASK;
@@ -1466,7 +1477,7 @@ static void cpsw_hwtstamp_v2(struct cpsw_priv *priv)
 
                if (priv->cpts->rx_enable)
                        ctrl |= CTRL_V3_RX_TS_BITS;
-       break;
+               break;
        }
 
        mtype = (30 << TS_SEQ_ID_OFFSET_SHIFT) | EVENT_MSG_BITS;
@@ -1589,10 +1600,8 @@ static void cpsw_ndo_tx_timeout(struct net_device *ndev)
        cpsw_err(priv, tx_err, "transmit timeout, restarting dma\n");
        ndev->stats.tx_errors++;
        cpsw_intr_disable(priv);
-       cpdma_ctlr_int_ctrl(priv->dma, false);
        cpdma_chan_stop(priv->txch);
        cpdma_chan_start(priv->txch);
-       cpdma_ctlr_int_ctrl(priv->dma, true);
        cpsw_intr_enable(priv);
 }
 
@@ -1629,10 +1638,8 @@ static void cpsw_ndo_poll_controller(struct net_device *ndev)
        struct cpsw_priv *priv = netdev_priv(ndev);
 
        cpsw_intr_disable(priv);
-       cpdma_ctlr_int_ctrl(priv->dma, false);
        cpsw_rx_interrupt(priv->irqs_table[0], priv);
        cpsw_tx_interrupt(priv->irqs_table[1], priv);
-       cpdma_ctlr_int_ctrl(priv->dma, true);
        cpsw_intr_enable(priv);
 }
 #endif
@@ -1783,7 +1790,6 @@ static void cpsw_get_drvinfo(struct net_device *ndev,
        strlcpy(info->driver, "cpsw", sizeof(info->driver));
        strlcpy(info->version, "1.0", sizeof(info->version));
        strlcpy(info->bus_info, priv->pdev->name, sizeof(info->bus_info));
-       info->regdump_len = cpsw_get_regs_len(ndev);
 }
 
 static u32 cpsw_get_msglevel(struct net_device *ndev)
@@ -1934,11 +1940,12 @@ static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv,
        slave->port_vlan = data->dual_emac_res_vlan;
 }
 
-static int cpsw_probe_dt(struct cpsw_platform_data *data,
+static int cpsw_probe_dt(struct cpsw_priv *priv,
                         struct platform_device *pdev)
 {
        struct device_node *node = pdev->dev.of_node;
        struct device_node *slave_node;
+       struct cpsw_platform_data *data = &priv->data;
        int i = 0, ret;
        u32 prop;
 
@@ -2019,32 +2026,54 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
        for_each_child_of_node(node, slave_node) {
                struct cpsw_slave_data *slave_data = data->slave_data + i;
                const void *mac_addr = NULL;
-               u32 phyid;
                int lenp;
                const __be32 *parp;
-               struct device_node *mdio_node;
-               struct platform_device *mdio;
 
                /* This is no slave child node, continue */
                if (strcmp(slave_node->name, "slave"))
                        continue;
 
+               priv->phy_node = of_parse_phandle(slave_node, "phy-handle", 0);
                parp = of_get_property(slave_node, "phy_id", &lenp);
-               if ((parp == NULL) || (lenp != (sizeof(void *) * 2))) {
-                       dev_err(&pdev->dev, "Missing slave[%d] phy_id property\n", i);
+               if (of_phy_is_fixed_link(slave_node)) {
+                       struct device_node *phy_node;
+                       struct phy_device *phy_dev;
+
+                       /* In the case of a fixed PHY, the DT node associated
+                        * to the PHY is the Ethernet MAC DT node.
+                        */
+                       ret = of_phy_register_fixed_link(slave_node);
+                       if (ret)
+                               return ret;
+                       phy_node = of_node_get(slave_node);
+                       phy_dev = of_phy_find_device(phy_node);
+                       if (!phy_dev)
+                               return -ENODEV;
+                       snprintf(slave_data->phy_id, sizeof(slave_data->phy_id),
+                                PHY_ID_FMT, phy_dev->bus->id, phy_dev->addr);
+               } else if (parp) {
+                       u32 phyid;
+                       struct device_node *mdio_node;
+                       struct platform_device *mdio;
+
+                       if (lenp != (sizeof(__be32) * 2)) {
+                               dev_err(&pdev->dev, "Invalid slave[%d] phy_id property\n", i);
+                               goto no_phy_slave;
+                       }
+                       mdio_node = of_find_node_by_phandle(be32_to_cpup(parp));
+                       phyid = be32_to_cpup(parp+1);
+                       mdio = of_find_device_by_node(mdio_node);
+                       of_node_put(mdio_node);
+                       if (!mdio) {
+                               dev_err(&pdev->dev, "Missing mdio platform device\n");
+                               return -EINVAL;
+                       }
+                       snprintf(slave_data->phy_id, sizeof(slave_data->phy_id),
+                                PHY_ID_FMT, mdio->name, phyid);
+               } else {
+                       dev_err(&pdev->dev, "No slave[%d] phy_id or fixed-link property\n", i);
                        goto no_phy_slave;
                }
-               mdio_node = of_find_node_by_phandle(be32_to_cpup(parp));
-               phyid = be32_to_cpup(parp+1);
-               mdio = of_find_device_by_node(mdio_node);
-               of_node_put(mdio_node);
-               if (!mdio) {
-                       dev_err(&pdev->dev, "Missing mdio platform device\n");
-                       return -EINVAL;
-               }
-               snprintf(slave_data->phy_id, sizeof(slave_data->phy_id),
-                        PHY_ID_FMT, mdio->name, phyid);
-
                slave_data->phy_if = of_get_phy_mode(slave_node);
                if (slave_data->phy_if < 0) {
                        dev_err(&pdev->dev, "Missing or malformed slave[%d] phy-mode property\n",
@@ -2057,13 +2086,10 @@ no_phy_slave:
                if (mac_addr) {
                        memcpy(slave_data->mac_addr, mac_addr, ETH_ALEN);
                } else {
-                       if (of_machine_is_compatible("ti,am33xx")) {
-                               ret = cpsw_am33xx_cm_get_macid(&pdev->dev,
-                                                       0x630, i,
-                                                       slave_data->mac_addr);
-                               if (ret)
-                                       return ret;
-                       }
+                       ret = ti_cm_get_macid(&pdev->dev, i,
+                                             slave_data->mac_addr);
+                       if (ret)
+                               return ret;
                }
                if (data->dual_emac) {
                        if (of_property_read_u32(slave_node, "dual_emac_res_vlan",
@@ -2146,7 +2172,6 @@ static int cpsw_probe_dual_emac(struct platform_device *pdev,
 
        ndev->netdev_ops = &cpsw_netdev_ops;
        ndev->ethtool_ops = &cpsw_ethtool_ops;
-       netif_napi_add(ndev, &priv_sl2->napi, cpsw_poll, CPSW_POLL_WEIGHT);
 
        /* register the network device */
        SET_NETDEV_DEV(ndev, &pdev->dev);
@@ -2160,6 +2185,44 @@ static int cpsw_probe_dual_emac(struct platform_device *pdev,
        return ret;
 }
 
+#define CPSW_QUIRK_IRQ         BIT(0)
+
+static struct platform_device_id cpsw_devtype[] = {
+       {
+               /* keep it for existing comaptibles */
+               .name = "cpsw",
+               .driver_data = CPSW_QUIRK_IRQ,
+       }, {
+               .name = "am335x-cpsw",
+               .driver_data = CPSW_QUIRK_IRQ,
+       }, {
+               .name = "am4372-cpsw",
+               .driver_data = 0,
+       }, {
+               .name = "dra7-cpsw",
+               .driver_data = 0,
+       }, {
+               /* sentinel */
+       }
+};
+MODULE_DEVICE_TABLE(platform, cpsw_devtype);
+
+enum ti_cpsw_type {
+       CPSW = 0,
+       AM335X_CPSW,
+       AM4372_CPSW,
+       DRA7_CPSW,
+};
+
+static const struct of_device_id cpsw_of_mtable[] = {
+       { .compatible = "ti,cpsw", .data = &cpsw_devtype[CPSW], },
+       { .compatible = "ti,am335x-cpsw", .data = &cpsw_devtype[AM335X_CPSW], },
+       { .compatible = "ti,am4372-cpsw", .data = &cpsw_devtype[AM4372_CPSW], },
+       { .compatible = "ti,dra7-cpsw", .data = &cpsw_devtype[DRA7_CPSW], },
+       { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, cpsw_of_mtable);
+
 static int cpsw_probe(struct platform_device *pdev)
 {
        struct cpsw_platform_data       *data;
@@ -2169,6 +2232,8 @@ static int cpsw_probe(struct platform_device *pdev)
        struct cpsw_ale_params          ale_params;
        void __iomem                    *ss_regs;
        struct resource                 *res, *ss_res;
+       const struct of_device_id       *of_id;
+       struct gpio_descs               *mode;
        u32 slave_offset, sliver_offset, slave_size;
        int ret = 0, i;
        int irq;
@@ -2188,13 +2253,19 @@ static int cpsw_probe(struct platform_device *pdev)
        priv->msg_enable = netif_msg_init(debug_level, CPSW_DEBUG);
        priv->rx_packet_max = max(rx_packet_max, 128);
        priv->cpts = devm_kzalloc(&pdev->dev, sizeof(struct cpts), GFP_KERNEL);
-       priv->irq_enabled = true;
        if (!priv->cpts) {
                dev_err(&pdev->dev, "error allocating cpts\n");
                ret = -ENOMEM;
                goto clean_ndev_ret;
        }
 
+       mode = devm_gpiod_get_array_optional(&pdev->dev, "mode", GPIOD_OUT_LOW);
+       if (IS_ERR(mode)) {
+               ret = PTR_ERR(mode);
+               dev_err(&pdev->dev, "gpio request failed, ret %d\n", ret);
+               goto clean_ndev_ret;
+       }
+
        /*
         * This may be required here for child devices.
         */
@@ -2203,7 +2274,7 @@ static int cpsw_probe(struct platform_device *pdev)
        /* Select default pin state */
        pinctrl_pm_select_default_state(&pdev->dev);
 
-       if (cpsw_probe_dt(&priv->data, pdev)) {
+       if (cpsw_probe_dt(priv, pdev)) {
                dev_err(&pdev->dev, "cpsw: platform data missing\n");
                ret = -ENODEV;
                goto clean_runtime_disable_ret;
@@ -2356,10 +2427,17 @@ static int cpsw_probe(struct platform_device *pdev)
        ndev->irq = platform_get_irq(pdev, 1);
        if (ndev->irq < 0) {
                dev_err(priv->dev, "error getting irq resource\n");
-               ret = -ENOENT;
+               ret = ndev->irq;
                goto clean_ale_ret;
        }
 
+       of_id = of_match_device(cpsw_of_mtable, &pdev->dev);
+       if (of_id) {
+               pdev->id_entry = of_id->data;
+               if (pdev->id_entry->driver_data)
+                       priv->quirk_irq = true;
+       }
+
        /* Grab RX and TX IRQs. Note that we also have RX_THRESHOLD and
         * MISC IRQs which are always kept disabled with this driver so
         * we will not request them.
@@ -2370,8 +2448,10 @@ static int cpsw_probe(struct platform_device *pdev)
 
        /* RX IRQ */
        irq = platform_get_irq(pdev, 1);
-       if (irq < 0)
+       if (irq < 0) {
+               ret = irq;
                goto clean_ale_ret;
+       }
 
        priv->irqs_table[0] = irq;
        ret = devm_request_irq(&pdev->dev, irq, cpsw_rx_interrupt,
@@ -2383,8 +2463,10 @@ static int cpsw_probe(struct platform_device *pdev)
 
        /* TX IRQ */
        irq = platform_get_irq(pdev, 2);
-       if (irq < 0)
+       if (irq < 0) {
+               ret = irq;
                goto clean_ale_ret;
+       }
 
        priv->irqs_table[1] = irq;
        ret = devm_request_irq(&pdev->dev, irq, cpsw_tx_interrupt,
@@ -2399,7 +2481,8 @@ static int cpsw_probe(struct platform_device *pdev)
 
        ndev->netdev_ops = &cpsw_netdev_ops;
        ndev->ethtool_ops = &cpsw_ethtool_ops;
-       netif_napi_add(ndev, &priv->napi, cpsw_poll, CPSW_POLL_WEIGHT);
+       netif_napi_add(ndev, &priv->napi_rx, cpsw_rx_poll, CPSW_POLL_WEIGHT);
+       netif_napi_add(ndev, &priv->napi_tx, cpsw_tx_poll, CPSW_POLL_WEIGHT);
 
        /* register the network device */
        SET_NETDEV_DEV(ndev, &pdev->dev);
@@ -2523,12 +2606,6 @@ static int cpsw_resume(struct device *dev)
 
 static SIMPLE_DEV_PM_OPS(cpsw_pm_ops, cpsw_suspend, cpsw_resume);
 
-static const struct of_device_id cpsw_of_mtable[] = {
-       { .compatible = "ti,cpsw", },
-       { /* sentinel */ },
-};
-MODULE_DEVICE_TABLE(of, cpsw_of_mtable);
-
 static struct platform_driver cpsw_driver = {
        .driver = {
                .name    = "cpsw",
@@ -2539,17 +2616,7 @@ static struct platform_driver cpsw_driver = {
        .remove = cpsw_remove,
 };
 
-static int __init cpsw_init(void)
-{
-       return platform_driver_register(&cpsw_driver);
-}
-late_initcall(cpsw_init);
-
-static void __exit cpsw_exit(void)
-{
-       platform_driver_unregister(&cpsw_driver);
-}
-module_exit(cpsw_exit);
+module_platform_driver(cpsw_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Cyril Chemparathy <cyril@ti.com>");