gmac: support clock control
authorhwg <hwg@rock-chips.com>
Mon, 21 Apr 2014 10:02:58 +0000 (18:02 +0800)
committerhwg <hwg@rock-chips.com>
Mon, 21 Apr 2014 10:04:40 +0000 (18:04 +0800)
arch/arm/boot/dts/rk3288.dtsi
drivers/net/ethernet/rockchip/gmac/stmmac.h
drivers/net/ethernet/rockchip/gmac/stmmac_main.c

index ef09f5b4411c79136aabe0cf8030d336764df417..4a1e0d801e7d6f5a84bb1976a4aed3d69a3858fb 100755 (executable)
                reg = <0xff290000 0x10000>;
                interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;  /*irq=59*/
                interrupt-names = "macirq";
+               clocks = <&clk_mac>, <&clk_gates5 0>,
+                         <&clk_gates5 1>, <&clk_gates5 2>,
+                         <&clk_gates5 3>, <&clk_gates8 0>,
+                         <&clk_gates8 1>;
+               clock-names = "clk_mac", "mac_clk_rx",
+                         "mac_clk_tx", "clk_mac_ref",
+                         "clk_mac_refout", "aclk_mac",
+                         "pclk_mac";   
                //phy-mode = "rmii";
                phy-mode = "rgmii";
                pinctrl-names = "default";
index 8f23e1106868485b28b4bbfaea54c0cd35cb909e..d6a879e8820bc9d679c84e01bbb3a04cc741550f 100755 (executable)
@@ -92,6 +92,14 @@ struct stmmac_priv {
        int wolopts;
        int wol_irq;
        struct clk *stmmac_clk;
+       struct clk *clk_mac;
+       struct clk *mac_clk_rx;
+       struct clk *mac_clk_tx;
+       struct clk *clk_mac_ref;
+       struct clk *clk_mac_refout;
+       struct clk *aclk_mac;
+       struct clk *pclk_mac;
+       bool clk_enable;
        int clk_csr;
        struct timer_list eee_ctrl_timer;
        int lpi_irq;
index 4fb91e954f059c3cc261c337db34f41889ef2c81..b6278e8f9de993d7fd27e77117d379ab053b2939 100755 (executable)
@@ -148,6 +148,38 @@ static void stmmac_exit_fs(void);
 
 #define STMMAC_COAL_TIMER(x) (jiffies + usecs_to_jiffies(x))
 
+static int gmac_clk_enable(struct stmmac_priv *priv)
+{
+       if (!priv->clk_enable) {
+               clk_prepare_enable(priv->clk_mac);
+               clk_prepare_enable(priv->mac_clk_rx);
+               clk_prepare_enable(priv->mac_clk_tx);
+               clk_prepare_enable(priv->clk_mac_ref);
+               clk_prepare_enable(priv->clk_mac_refout);
+               clk_prepare_enable(priv->aclk_mac);
+               clk_prepare_enable(priv->pclk_mac);
+               priv->clk_enable = true;
+       }
+       
+       return 0;
+}
+
+static int gmac_clk_disable(struct stmmac_priv *priv)
+{
+       if (priv->clk_enable) {
+               clk_disable_unprepare(priv->clk_mac);
+               clk_disable_unprepare(priv->mac_clk_rx);
+               clk_disable_unprepare(priv->mac_clk_tx);
+               clk_disable_unprepare(priv->clk_mac_ref);
+               clk_disable_unprepare(priv->clk_mac_refout);
+               clk_disable_unprepare(priv->aclk_mac);
+               clk_disable_unprepare(priv->pclk_mac);
+               priv->clk_enable = false;
+       }
+       
+       return 0;
+}
+
 /**
  * stmmac_verify_args - verify the driver parameters.
  * Description: it verifies if some wrong parameter is passed to the driver.
@@ -1570,6 +1602,7 @@ static int stmmac_open(struct net_device *dev)
        int ret;
 
        clk_prepare_enable(priv->stmmac_clk);
+       gmac_clk_enable(priv);
 
        if ((priv->plat) && (priv->plat->bsp_priv)) {
                struct bsp_priv * bsp_priv = priv->plat->bsp_priv;
@@ -1721,6 +1754,7 @@ open_error:
                phy_disconnect(priv->phydev);
 
        clk_disable_unprepare(priv->stmmac_clk);
+       gmac_clk_disable(priv);
 
        return ret;
 }
@@ -1774,6 +1808,7 @@ static int stmmac_release(struct net_device *dev)
        stmmac_exit_fs();
 #endif
        clk_disable_unprepare(priv->stmmac_clk);
+       gmac_clk_disable(priv);
 
        stmmac_release_ptp(priv);
 
@@ -2728,6 +2763,49 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
                goto error_netdev_register;
        }
 
+       priv->clk_enable = 0;
+       priv->clk_mac = clk_get(priv->device,"clk_mac");
+       if (IS_ERR(priv->clk_mac)) {
+               pr_warn("%s: warning: cannot get clk_mac clock\n", __func__);
+               goto error_clk_get;
+       }
+
+       priv->mac_clk_rx = clk_get(priv->device,"mac_clk_rx");
+       if (IS_ERR(priv->mac_clk_rx)) {
+               pr_warn("%s: warning: cannot get mac_clk_rx clock\n", __func__);
+               goto error_clk_get;
+       }
+
+       priv->mac_clk_tx = clk_get(priv->device,"mac_clk_tx");
+       if (IS_ERR(priv->mac_clk_tx)) {
+               pr_warn("%s: warning: cannot get mac_clk_tx clock\n", __func__);
+               goto error_clk_get;
+       }
+
+       priv->clk_mac_ref = clk_get(priv->device,"clk_mac_ref");
+       if (IS_ERR(priv->clk_mac_ref)) {
+               pr_warn("%s: warning: cannot get clk_mac_ref clock\n", __func__);
+               goto error_clk_get;
+       }
+
+       priv->clk_mac_refout = clk_get(priv->device,"clk_mac_refout");
+       if (IS_ERR(priv->clk_mac_refout)) {
+               pr_warn("%s: warning: cannot get clk_mac_refout clock\n", __func__);
+               goto error_clk_get;
+       }
+
+       priv->aclk_mac = clk_get(priv->device,"aclk_mac");
+       if (IS_ERR(priv->aclk_mac)) {
+               pr_warn("%s: warning: cannot get aclk_mac clock\n", __func__);
+               goto error_clk_get;
+       }
+
+       priv->pclk_mac = clk_get(priv->device,"pclk_mac");
+       if (IS_ERR(priv->pclk_mac)) {
+               pr_warn("%s: warning: cannot get pclk_mac clock\n", __func__);
+               goto error_clk_get;
+       }
+
        priv->stmmac_clk = clk_get(priv->device, "clk_mac"/*STMMAC_RESOURCE_NAME*/);
        if (IS_ERR(priv->stmmac_clk)) {
                pr_warn("%s: warning: cannot get CSR clock\n", __func__);
@@ -2751,6 +2829,13 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
 
 error_mdio_register:
        clk_put(priv->stmmac_clk);
+       clk_put(priv->clk_mac);
+       clk_put(priv->mac_clk_rx);
+       clk_put(priv->mac_clk_tx);
+       clk_put(priv->clk_mac_ref);
+       clk_put(priv->clk_mac_refout);
+       clk_put(priv->aclk_mac);
+       clk_put(priv->pclk_mac);
 error_clk_get:
        unregister_netdev(ndev);
 error_netdev_register:
@@ -2819,6 +2904,7 @@ int stmmac_suspend(struct net_device *ndev)
                stmmac_set_mac(priv->ioaddr, false);
                /* Disable clock in case of PWM is off */
                clk_disable_unprepare(priv->stmmac_clk);
+               gmac_clk_disable(priv);
        }
        spin_unlock_irqrestore(&priv->lock, flags);
        return 0;
@@ -2842,9 +2928,11 @@ int stmmac_resume(struct net_device *ndev)
         */
        if (device_may_wakeup(priv->device))
                priv->hw->mac->pmt(priv->ioaddr, 0);
-       else
+       else {
                /* enable the clk prevously disabled */
                clk_prepare_enable(priv->stmmac_clk);
+               gmac_clk_enable(priv);
+       }
 
        netif_device_attach(ndev);