This removes the default clocking for the MMCI controller so that
the external MCI card clock does not activate until the first
.set_ios() call is issued. It will further handle the transitions
from a clock != 0 to 0 and vice versa by gating/ungating the
clock with clk_disable()/clk_enable().

This assures that the MCI clock will not be active unless there
is a card in the MMC slot.

By default the MMC core will not gate off the clock to a card
once it's enabled, but with the separate patch for aggressive
clocking this can optionally be enabled for the system.

Signed-off-by: Linus Walleij <[email protected]>
---
 drivers/mmc/host/mmci.c |   35 +++++++++++++++++++++++------------
 drivers/mmc/host/mmci.h |    1 +
 2 files changed, 24 insertions(+), 12 deletions(-)

diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index d4081d5..ea5e320 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -924,7 +924,23 @@ static void mmci_set_ios(struct mmc_host *mmc, struct 
mmc_ios *ios)
 
        spin_lock_irqsave(&host->lock, flags);
 
-       mmci_set_clkreg(host, ios->clock);
+       /*
+        * Turn on clock whenever ios->clock transitions
+        * from 0 to !=0 and gate it off whenever ios->clock
+        * transitions from !=0 to 0.
+        */
+       if (host->iosclock == 0 && ios->clock != 0) {
+               dev_dbg(mmc_dev(mmc), "enable clock f=%d\n", ios->clock);
+               clk_enable(host->clk);
+               mmci_set_clkreg(host, ios->clock);
+       } else if (host->iosclock != 0 && ios->clock == 0) {
+               dev_dbg(mmc_dev(mmc), "disable clock\n");
+               clk_disable(host->clk);
+       } else if (ios->clock != 0) {
+               mmci_set_clkreg(host, ios->clock);
+               dev_dbg(mmc_dev(mmc), "set clock f=%d\n", ios->clock);
+       }
+       host->iosclock = ios->clock;
 
        if (host->pwr != pwr) {
                host->pwr = pwr;
@@ -1009,6 +1025,8 @@ static int __devinit mmci_probe(struct amba_device *dev, 
struct amba_id *id)
 
        host = mmc_priv(mmc);
        host->mmc = mmc;
+       host->plat = plat;
+       host->variant = variant;
 
        host->gpio_wp = -ENOSYS;
        host->gpio_cd = -ENOSYS;
@@ -1019,19 +1037,14 @@ static int __devinit mmci_probe(struct amba_device 
*dev, struct amba_id *id)
        dev_dbg(mmc_dev(mmc), "designer ID = 0x%02x\n", host->hw_designer);
        dev_dbg(mmc_dev(mmc), "revision = 0x%01x\n", host->hw_revision);
 
+       /* This clock will be enabled/disabled by set_ios() calls later */
        host->clk = clk_get(&dev->dev, NULL);
        if (IS_ERR(host->clk)) {
                ret = PTR_ERR(host->clk);
                host->clk = NULL;
                goto host_free;
        }
-
-       ret = clk_enable(host->clk);
-       if (ret)
-               goto clk_free;
-
-       host->plat = plat;
-       host->variant = variant;
+       host->iosclock = 0;
        host->mclk = clk_get_rate(host->clk);
        /*
         * According to the spec, mclk is max 100 MHz,
@@ -1041,7 +1054,7 @@ static int __devinit mmci_probe(struct amba_device *dev, 
struct amba_id *id)
        if (host->mclk > 100000000) {
                ret = clk_set_rate(host->clk, 100000000);
                if (ret < 0)
-                       goto clk_disable;
+                       goto clk_free;
                host->mclk = clk_get_rate(host->clk);
                dev_dbg(mmc_dev(mmc), "eventual mclk rate: %u Hz\n",
                        host->mclk);
@@ -1050,7 +1063,7 @@ static int __devinit mmci_probe(struct amba_device *dev, 
struct amba_id *id)
        host->base = ioremap(dev->res.start, resource_size(&dev->res));
        if (!host->base) {
                ret = -ENOMEM;
-               goto clk_disable;
+               goto clk_free;
        }
 
        mmc->ops = &mmci_ops;
@@ -1203,8 +1216,6 @@ static int __devinit mmci_probe(struct amba_device *dev, 
struct amba_id *id)
                gpio_free(host->gpio_cd);
  err_gpio_cd:
        iounmap(host->base);
- clk_disable:
-       clk_disable(host->clk);
  clk_free:
        clk_put(host->clk);
  host_free:
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index bc3b71e..5701d33 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -170,6 +170,7 @@ struct mmci_host {
 
        unsigned int            mclk;
        unsigned int            cclk;
+       unsigned int            iosclock;
        u32                     pwr;
        struct mmci_platform_data *plat;
        struct variant_data     *variant;
-- 
1.7.2.3

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to