stmmac: add clk management support

this patch adds the way to enable/disable the MAC
clock when call the open/close and resume/restore
functions.
This has been tested on ST platforms and SPEAr; thanks
to Francesco and Deepak.

Signed-off-by: Deepak Sikri <deepak.sikri@st.com>
Tested-by: Francesco Virlinzi <francesco.virlinzi@st.com>
Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Giuseppe CAVALLARO 2012-04-04 04:33:25 +00:00 committed by David S. Miller
parent 39b401dbd3
commit ba1377ffe9
2 changed files with 63 additions and 5 deletions

View File

@ -22,6 +22,8 @@
#define STMMAC_RESOURCE_NAME "stmmaceth"
#define DRV_MODULE_VERSION "Feb_2012"
#include <linux/clk.h>
#include <linux/stmmac.h>
#include <linux/phy.h>
#include "common.h"
@ -79,6 +81,9 @@ struct stmmac_priv {
struct stmmac_counters mmc;
struct dma_features dma_cap;
int hw_cap_support;
#ifdef CONFIG_HAVE_CLK
struct clk *stmmac_clk;
#endif
};
extern int phyaddr;
@ -97,3 +102,41 @@ int stmmac_dvr_remove(struct net_device *ndev);
struct stmmac_priv *stmmac_dvr_probe(struct device *device,
struct plat_stmmacenet_data *plat_dat,
void __iomem *addr);
#ifdef CONFIG_HAVE_CLK
static inline int stmmac_clk_enable(struct stmmac_priv *priv)
{
if (priv->stmmac_clk)
return clk_enable(priv->stmmac_clk);
return 0;
}
static inline void stmmac_clk_disable(struct stmmac_priv *priv)
{
if (priv->stmmac_clk)
clk_disable(priv->stmmac_clk);
}
static inline int stmmac_clk_get(struct stmmac_priv *priv)
{
priv->stmmac_clk = clk_get(priv->device, NULL);
if (IS_ERR(priv->stmmac_clk)) {
pr_err("%s: ERROR clk_get failed\n", __func__);
return PTR_ERR(priv->stmmac_clk);
}
return 0;
}
#else
static inline int stmmac_clk_enable(struct stmmac_priv *priv)
{
return 0;
}
static inline void stmmac_clk_disable(struct stmmac_priv *priv)
{
}
static inline int stmmac_clk_get(struct stmmac_priv *priv)
{
return 0;
}
#endif /* CONFIG_HAVE_CLK */

View File

@ -904,6 +904,8 @@ static int stmmac_open(struct net_device *dev)
struct stmmac_priv *priv = netdev_priv(dev);
int ret;
stmmac_clk_enable(priv);
stmmac_check_ether_addr(priv);
/* MDIO bus Registration */
@ -911,13 +913,15 @@ static int stmmac_open(struct net_device *dev)
if (ret < 0) {
pr_debug("%s: MDIO bus (id: %d) registration failed",
__func__, priv->plat->bus_id);
return ret;
goto open_clk_dis;
}
#ifdef CONFIG_STMMAC_TIMER
priv->tm = kzalloc(sizeof(struct stmmac_timer *), GFP_KERNEL);
if (unlikely(priv->tm == NULL))
return -ENOMEM;
if (unlikely(priv->tm == NULL)) {
ret = -ENOMEM;
goto open_clk_dis;
}
priv->tm->freq = tmrate;
@ -1034,6 +1038,8 @@ open_error:
if (priv->phydev)
phy_disconnect(priv->phydev);
open_clk_dis:
stmmac_clk_disable(priv);
return ret;
}
@ -1086,6 +1092,7 @@ static int stmmac_release(struct net_device *dev)
stmmac_exit_fs();
#endif
stmmac_mdio_unregister(dev);
stmmac_clk_disable(priv);
return 0;
}
@ -1880,6 +1887,9 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
goto error;
}
if (stmmac_clk_get(priv))
goto error;
return priv;
error:
@ -1949,9 +1959,11 @@ int stmmac_suspend(struct net_device *ndev)
/* Enable Power down mode by programming the PMT regs */
if (device_may_wakeup(priv->device))
priv->hw->mac->pmt(priv->ioaddr, priv->wolopts);
else
else {
stmmac_set_mac(priv->ioaddr, false);
/* Disable clock in case of PWM is off */
stmmac_clk_disable(priv);
}
spin_unlock(&priv->lock);
return 0;
}
@ -1972,6 +1984,9 @@ int stmmac_resume(struct net_device *ndev)
* from another devices (e.g. serial console). */
if (device_may_wakeup(priv->device))
priv->hw->mac->pmt(priv->ioaddr, 0);
else
/* enable the clk prevously disabled */
stmmac_clk_enable(priv);
netif_device_attach(ndev);