rk29 vmac: add suspend and resume function
authorlyx <lyx@rock-chips.com>
Mon, 15 Aug 2011 08:33:59 +0000 (01:33 -0700)
committerlyx <lyx@rock-chips.com>
Mon, 15 Aug 2011 08:36:13 +0000 (01:36 -0700)
drivers/net/rk29_vmac.c

index b717935509a514601dea31f008bf83db3c6c2b11..d83f6f4daafc622944372cd3904c7d0bdd6104c9 100755 (executable)
@@ -1029,6 +1029,8 @@ int vmac_open(struct net_device *dev)
        struct clk *arm_clk = NULL;\r
        struct rk29_vmac_platform_data *pdata = ap->pdev->dev.platform_data;\r
 \r
+       printk("enter func %s...\n", __func__);\r
+\r
        if (ap == NULL)\r
                return -ENODEV;\r
 \r
@@ -1042,6 +1044,7 @@ int vmac_open(struct net_device *dev)
                wake_lock(&idlelock);\r
        \r
        clk_set_rate(mac_clk, 50000000);\r
+       clk_enable(mac_clk);\r
        clk_enable(clk_get(NULL,"mii_rx"));\r
        clk_enable(clk_get(NULL,"mii_tx"));\r
        clk_enable(clk_get(NULL,"hclk_mac"));\r
@@ -1131,6 +1134,8 @@ int vmac_close(struct net_device *dev)
        struct clk *mac_parent = NULL;\r
        struct rk29_vmac_platform_data *pdata = ap->pdev->dev.platform_data;\r
 \r
+       printk("enter func %s...\n", __func__);\r
+\r
        netif_stop_queue(dev);\r
        napi_disable(&ap->napi);\r
 \r
@@ -1171,6 +1176,7 @@ int vmac_close(struct net_device *dev)
        if (arm_clk && mac_parent && (arm_clk == mac_parent))\r
                wake_unlock(&idlelock);\r
        \r
+       clk_disable(mac_clk);\r
        clk_disable(clk_get(NULL,"mii_rx"));\r
        clk_disable(clk_get(NULL,"mii_tx"));\r
        clk_disable(clk_get(NULL,"hclk_mac"));\r
@@ -1179,6 +1185,68 @@ int vmac_close(struct net_device *dev)
        return 0;\r
 }\r
 \r
+static void rk29_init_vmac(struct net_device *dev)\r
+{\r
+       struct vmac_priv *ap = netdev_priv(dev);\r
+       unsigned int temp;\r
+       struct clk *mac_clk = NULL;\r
+       struct rk29_vmac_platform_data *pdata = ap->pdev->dev.platform_data;\r
+\r
+       printk("enter func %s...\n", __func__);\r
+               \r
+       //set rmii ref clock 50MHz\r
+       mac_clk = clk_get(NULL, "mac_ref_div"); \r
+       clk_set_rate(mac_clk, 50000000);\r
+       clk_enable(mac_clk);\r
+       clk_enable(clk_get(NULL,"mii_rx"));\r
+       clk_enable(clk_get(NULL,"mii_tx"));\r
+       clk_enable(clk_get(NULL,"hclk_mac"));\r
+       clk_enable(clk_get(NULL,"mac_ref"));\r
+\r
+       //phy power on\r
+       if (pdata && pdata->rmii_power_control)\r
+               pdata->rmii_power_control(1);\r
+\r
+       msleep(1000);\r
+\r
+       /* IRQ mask */\r
+       temp = RXINT_MASK | ERR_MASK | TXCH_MASK | MDIO_MASK;\r
+       vmac_writel(ap, temp, ENABLE);\r
+\r
+       /* Set control */\r
+       temp = (RX_BDT_LEN << 24) | (TX_BDT_LEN << 16) | TXRN_MASK | RXRN_MASK;\r
+       vmac_writel(ap, temp, CONTROL);\r
+\r
+       /* enable, after all other bits are set */\r
+       vmac_writel(ap, temp | EN_MASK, CONTROL);\r
+}\r
+\r
+static void rk29_vmac_shutdown(struct net_device *dev)\r
+{\r
+       struct vmac_priv *ap = netdev_priv(dev);\r
+       struct rk29_vmac_platform_data *pdata = ap->pdev->dev.platform_data;\r
+       \r
+       printk("enter func %s...\n", __func__);\r
+                                       \r
+       /* disable interrupts */\r
+       vmac_writel(ap, 0, ENABLE);\r
+       \r
+       /* turn off vmac */\r
+       vmac_writel(ap, 0, CONTROL);\r
+                       \r
+       //phy power off\r
+       if (pdata && pdata->rmii_power_control)\r
+               pdata->rmii_power_control(0);\r
+       \r
+       //clock close\r
+       clk_disable(clk_get(NULL, "mac_ref_div"));              \r
+       clk_disable(clk_get(NULL,"mii_rx"));\r
+       clk_disable(clk_get(NULL,"mii_tx"));\r
+       clk_disable(clk_get(NULL,"hclk_mac"));\r
+       clk_disable(clk_get(NULL,"mac_ref"));\r
+}\r
+\r
+\r
 void vmac_update_stats(struct vmac_priv *ap)\r
 {\r
        struct net_device_stats *_stats = &ap->stats;\r
@@ -1538,11 +1606,49 @@ static int __devexit vmac_remove(struct platform_device *pdev)
        return 0;\r
 }\r
 \r
+static int\r
+rk29_vmac_suspend(struct device *dev)\r
+{\r
+       struct platform_device *pdev = to_platform_device(dev);\r
+       struct net_device *ndev = platform_get_drvdata(pdev);\r
+\r
+       if (ndev) {\r
+               if (netif_running(ndev)) {\r
+                       netif_device_detach(ndev);\r
+                       rk29_vmac_shutdown(ndev);\r
+               }\r
+       }\r
+       return 0;\r
+}\r
+\r
+static int\r
+rk29_vmac_resume(struct device *dev)\r
+{\r
+       struct platform_device *pdev = to_platform_device(dev);\r
+       struct net_device *ndev = platform_get_drvdata(pdev);\r
+\r
+       if (ndev) {\r
+               if (netif_running(ndev)) {\r
+                       rk29_init_vmac(ndev);\r
+                       netif_device_attach(ndev);\r
+               }\r
+       }\r
+       return 0;\r
+}\r
+\r
+static struct dev_pm_ops rk29_vmac_pm_ops = {\r
+       .suspend        = rk29_vmac_suspend,\r
+       .resume         = rk29_vmac_resume,\r
+};\r
+\r
+\r
 static struct platform_driver rk29_vmac_driver = {\r
        .probe          = vmac_probe,\r
        .remove         = __devexit_p(vmac_remove),\r
        .driver         = {\r
                .name           = "rk29 vmac",\r
+               .owner   = THIS_MODULE,\r
+               .pm  = &rk29_vmac_pm_ops,\r
        },\r
 };\r
 \r