diff mbox

[RFC,RESEND] sdhci-s3c: support clock enable/disable (clock-gating)

Message ID 4C91BD5A.1040804@samsung.com (mailing list archive)
State New, archived
Headers show

Commit Message

Jaehoon Chung Sept. 16, 2010, 6:46 a.m. UTC
None
diff mbox

Patch

diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c
index 71ad416..9b430fb 100644
--- a/drivers/mmc/host/sdhci-s3c.c
+++ b/drivers/mmc/host/sdhci-s3c.c
@@ -47,6 +47,7 @@  struct sdhci_s3c {
 	unsigned int		cur_clk;
 	int			ext_cd_irq;
 	int			ext_cd_gpio;
+	int			flag;
 
 	struct clk		*clk_io;
 	struct clk		*clk_bus[MAX_BUS_CLK];
@@ -232,10 +233,45 @@  static unsigned int sdhci_s3c_get_min_clock(struct sdhci_host *host)
 	return min;
 }
 
+static int sdhci_s3c_enable_clk(struct sdhci_host *host)
+{
+	struct sdhci_s3c *sc = to_s3c(host);
+
+	if (sc->flag != 1) {
+		clk_disable(sc->clk_io);
+		clk_disable(sc->clk_bus[sc->cur_clk]);
+	}
+
+	if (sc->host->clk_cnt == 0) {
+		clk_enable(sc->clk_io);
+		clk_enable(sc->clk_bus[sc->cur_clk]);
+		sc->host->clk_cnt++;
+		sc->flag = 1;
+	}
+
+	return 0;
+}
+
+static int sdhci_s3c_disable_clk(struct sdhci_host *host, int lazy)
+{
+	struct sdhci_s3c *sc = to_s3c(host);
+
+	if (sc->host->clk_cnt) {
+		clk_disable(sc->clk_io);
+		clk_disable(sc->clk_bus[sc->cur_clk]);
+		if (sc->host->clk_cnt)
+			sc->host->clk_cnt--;
+	}
+
+	return 0;
+}
+
 static struct sdhci_ops sdhci_s3c_ops = {
 	.get_max_clock		= sdhci_s3c_get_max_clk,
 	.set_clock		= sdhci_s3c_set_clock,
 	.get_min_clock		= sdhci_s3c_get_min_clock,
+	.enable			= sdhci_s3c_enable_clk,
+	.disable		= sdhci_s3c_disable_clk,
 };
 
 static void sdhci_s3c_notify_change(struct platform_device *dev, int state)
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 401527d..fa2e55d 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1245,7 +1245,37 @@  out:
 	spin_unlock_irqrestore(&host->lock, flags);
 }
 
+static int sdhci_enable_clk(struct mmc_host *mmc)
+{
+	struct sdhci_host *host = mmc_priv(mmc);
+	int ret = 0;
+
+	if (host->old_clock != 0 && host->clock == 0) {
+		if (host->ops->enable)
+			ret = host->ops->enable(host);
+		sdhci_set_clock(host, host->old_clock);
+	}
+
+	return ret;
+}
+
+static int sdhci_disable_clk(struct mmc_host *mmc, int lazy)
+{
+	struct sdhci_host *host = mmc_priv(mmc);
+	int ret = 0;
+
+	if (host->clock != 0) {
+		host->old_clock = host->clock;
+		sdhci_set_clock(host, 0);
+		if (host->ops->disable)
+			ret = host->ops->disable(host, lazy);
+	}
+	return ret;
+}
+
 static const struct mmc_host_ops sdhci_ops = {
+	.enable		= sdhci_enable_clk,
+	.disable	= sdhci_disable_clk,
 	.request	= sdhci_request,
 	.set_ios	= sdhci_set_ios,
 	.get_ro		= sdhci_get_ro,
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index d316bc7..0c6f143 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -278,6 +278,8 @@  struct sdhci_host {
 	unsigned int		timeout_clk;	/* Timeout freq (KHz) */
 
 	unsigned int		clock;		/* Current clock (MHz) */
+	unsigned int		old_clock;	/* Old clock (MHz) */
+	unsigned int		clk_cnt;	/* Clock user count */
 	u8			pwr;		/* Current voltage */
 
 	struct mmc_request	*mrq;		/* Current request */
@@ -323,6 +325,8 @@  struct sdhci_ops {
 	unsigned int	(*get_max_clock)(struct sdhci_host *host);
 	unsigned int	(*get_min_clock)(struct sdhci_host *host);
 	unsigned int	(*get_timeout_clock)(struct sdhci_host *host);
+	int		(*enable)(struct sdhci_host *host);
+	int		(*disable)(struct sdhci_host *host, int lazy);
 };
 
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS