mmc: omap_hsmmc: add runtime pm support
authorBalaji T K <balajitk@ti.com>
Fri, 1 Jul 2011 16:39:35 +0000 (22:09 +0530)
committerChris Ball <cjb@laptop.org>
Wed, 20 Jul 2011 21:21:17 +0000 (17:21 -0400)
* Add runtime pm support to HSMMC host controller.
* Use runtime pm API to enable/disable HSMMC clock.
* Use runtime autosuspend APIs to enable auto suspend delay.

Based on OMAP HSMMC runtime implementation by Kevin Hilman and
Kishore Kadiyala.

Signed-off-by: Balaji T K <balajitk@ti.com>
Signed-off-by: Chris Ball <cjb@laptop.org>
drivers/mmc/host/omap_hsmmc.c

index c7de6d62b943633dfb6a5249954ea072bb0bdd16..10122b1cc4240fedb644b168ac39659c793b72bc 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/semaphore.h>
 #include <linux/gpio.h>
 #include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
 #include <plat/dma.h>
 #include <mach/hardware.h>
 #include <plat/board.h>
 #define OMAP_MMC4_DEVID                3
 #define OMAP_MMC5_DEVID                4
 
+#define MMC_AUTOSUSPEND_DELAY  100
 #define MMC_TIMEOUT_MS         20
 #define OMAP_MMC_MASTER_CLOCK  96000000
 #define DRIVER_NAME            "omap_hsmmc"
@@ -1156,8 +1158,7 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd)
        int ret;
 
        /* Disable the clocks */
-       clk_disable(host->fclk);
-       clk_disable(host->iclk);
+       pm_runtime_put_sync(host->dev);
        if (host->got_dbclk)
                clk_disable(host->dbclk);
 
@@ -1168,8 +1169,7 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd)
        if (!ret)
                ret = mmc_slot(host).set_power(host->dev, host->slot_id, 1,
                                               vdd);
-       clk_enable(host->iclk);
-       clk_enable(host->fclk);
+       pm_runtime_get_sync(host->dev);
        if (host->got_dbclk)
                clk_enable(host->dbclk);
 
@@ -1605,7 +1605,7 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        u32 con;
        int do_send_init_stream = 0;
 
-       mmc_host_enable(host->mmc);
+       pm_runtime_get_sync(host->dev);
 
        if (ios->power_mode != host->power_mode) {
                switch (ios->power_mode) {
@@ -1700,8 +1700,7 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        else
                OMAP_HSMMC_WRITE(host->base, CON, con & ~OD);
 
-       if (host->power_mode == MMC_POWER_OFF)
-               mmc_host_disable(host->mmc);
+       pm_runtime_put_autosuspend(host->dev);
 }
 
 static int omap_hsmmc_get_cd(struct mmc_host *mmc)
@@ -1760,13 +1759,9 @@ static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host)
 static int omap_hsmmc_enable_fclk(struct mmc_host *mmc)
 {
        struct omap_hsmmc_host *host = mmc_priv(mmc);
-       int err;
 
-       err = clk_enable(host->fclk);
-       if (err)
-               return err;
-       dev_dbg(mmc_dev(host->mmc), "mmc_fclk: enabled\n");
-       omap_hsmmc_context_restore(host);
+       pm_runtime_get_sync(host->dev);
+
        return 0;
 }
 
@@ -1774,9 +1769,9 @@ static int omap_hsmmc_disable_fclk(struct mmc_host *mmc, int lazy)
 {
        struct omap_hsmmc_host *host = mmc_priv(mmc);
 
-       omap_hsmmc_context_save(host);
-       clk_disable(host->fclk);
-       dev_dbg(mmc_dev(host->mmc), "mmc_fclk: disabled\n");
+       pm_runtime_mark_last_busy(host->dev);
+       pm_runtime_put_autosuspend(host->dev);
+
        return 0;
 }
 
@@ -1819,10 +1814,7 @@ static int omap_hsmmc_regs_show(struct seq_file *s, void *data)
                return 0;
        }
 
-       if (clk_enable(host->fclk) != 0) {
-               seq_printf(s, "can't read the regs\n");
-               return 0;
-       }
+       pm_runtime_get_sync(host->dev);
 
        seq_printf(s, "SYSCONFIG:\t0x%08x\n",
                        OMAP_HSMMC_READ(host->base, SYSCONFIG));
@@ -1839,7 +1831,8 @@ static int omap_hsmmc_regs_show(struct seq_file *s, void *data)
        seq_printf(s, "CAPA:\t\t0x%08x\n",
                        OMAP_HSMMC_READ(host->base, CAPA));
 
-       clk_disable(host->fclk);
+       pm_runtime_mark_last_busy(host->dev);
+       pm_runtime_put_autosuspend(host->dev);
 
        return 0;
 }
@@ -1960,18 +1953,10 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
 
        mmc->caps |= MMC_CAP_DISABLE;
 
-       if (clk_enable(host->iclk) != 0) {
-               clk_put(host->iclk);
-               clk_put(host->fclk);
-               goto err1;
-       }
-
-       if (mmc_host_enable(host->mmc) != 0) {
-               clk_disable(host->iclk);
-               clk_put(host->iclk);
-               clk_put(host->fclk);
-               goto err1;
-       }
+       pm_runtime_enable(host->dev);
+       pm_runtime_get_sync(host->dev);
+       pm_runtime_set_autosuspend_delay(host->dev, MMC_AUTOSUSPEND_DELAY);
+       pm_runtime_use_autosuspend(host->dev);
 
        if (cpu_is_omap2430()) {
                host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck");
@@ -2098,6 +2083,8 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
        }
 
        omap_hsmmc_debugfs(mmc);
+       pm_runtime_mark_last_busy(host->dev);
+       pm_runtime_put_autosuspend(host->dev);
 
        return 0;
 
@@ -2113,8 +2100,8 @@ err_reg:
 err_irq_cd_init:
        free_irq(host->irq, host);
 err_irq:
-       mmc_host_disable(host->mmc);
-       clk_disable(host->iclk);
+       pm_runtime_mark_last_busy(host->dev);
+       pm_runtime_put_autosuspend(host->dev);
        clk_put(host->fclk);
        clk_put(host->iclk);
        if (host->got_dbclk) {
@@ -2138,7 +2125,7 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
        struct resource *res;
 
        if (host) {
-               mmc_host_enable(host->mmc);
+               pm_runtime_get_sync(host->dev);
                mmc_remove_host(host->mmc);
                if (host->use_reg)
                        omap_hsmmc_reg_put(host);
@@ -2149,8 +2136,8 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
                        free_irq(mmc_slot(host).card_detect_irq, host);
                flush_work_sync(&host->mmc_carddetect_work);
 
-               mmc_host_disable(host->mmc);
-               clk_disable(host->iclk);
+               pm_runtime_put_sync(host->dev);
+               pm_runtime_disable(host->dev);
                clk_put(host->fclk);
                clk_put(host->iclk);
                if (host->got_dbclk) {
@@ -2182,6 +2169,7 @@ static int omap_hsmmc_suspend(struct device *dev)
                return 0;
 
        if (host) {
+               pm_runtime_get_sync(host->dev);
                host->suspended = 1;
                if (host->pdata->suspend) {
                        ret = host->pdata->suspend(&pdev->dev,
@@ -2196,13 +2184,11 @@ static int omap_hsmmc_suspend(struct device *dev)
                }
                cancel_work_sync(&host->mmc_carddetect_work);
                ret = mmc_suspend_host(host->mmc);
-               mmc_host_enable(host->mmc);
+
                if (ret == 0) {
                        omap_hsmmc_disable_irq(host);
                        OMAP_HSMMC_WRITE(host->base, HCTL,
                                OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP);
-                       mmc_host_disable(host->mmc);
-                       clk_disable(host->iclk);
                        if (host->got_dbclk)
                                clk_disable(host->dbclk);
                } else {
@@ -2214,9 +2200,8 @@ static int omap_hsmmc_suspend(struct device *dev)
                                        dev_dbg(mmc_dev(host->mmc),
                                                "Unmask interrupt failed\n");
                        }
-                       mmc_host_disable(host->mmc);
                }
-
+               pm_runtime_put_sync(host->dev);
        }
        return ret;
 }
@@ -2232,14 +2217,7 @@ static int omap_hsmmc_resume(struct device *dev)
                return 0;
 
        if (host) {
-               ret = clk_enable(host->iclk);
-               if (ret)
-                       goto clk_en_err;
-
-               if (mmc_host_enable(host->mmc) != 0) {
-                       clk_disable(host->iclk);
-                       goto clk_en_err;
-               }
+               pm_runtime_get_sync(host->dev);
 
                if (host->got_dbclk)
                        clk_enable(host->dbclk);
@@ -2259,14 +2237,13 @@ static int omap_hsmmc_resume(struct device *dev)
                ret = mmc_resume_host(host->mmc);
                if (ret == 0)
                        host->suspended = 0;
+
+               pm_runtime_mark_last_busy(host->dev);
+               pm_runtime_put_autosuspend(host->dev);
        }
 
        return ret;
 
-clk_en_err:
-       dev_dbg(mmc_dev(host->mmc),
-               "Failed to enable MMC clocks during resume\n");
-       return ret;
 }
 
 #else
@@ -2274,9 +2251,33 @@ clk_en_err:
 #define omap_hsmmc_resume              NULL
 #endif
 
+static int omap_hsmmc_runtime_suspend(struct device *dev)
+{
+       struct omap_hsmmc_host *host;
+
+       host = platform_get_drvdata(to_platform_device(dev));
+       omap_hsmmc_context_save(host);
+       dev_dbg(mmc_dev(host->mmc), "disabled\n");
+
+       return 0;
+}
+
+static int omap_hsmmc_runtime_resume(struct device *dev)
+{
+       struct omap_hsmmc_host *host;
+
+       host = platform_get_drvdata(to_platform_device(dev));
+       omap_hsmmc_context_restore(host);
+       dev_dbg(mmc_dev(host->mmc), "enabled\n");
+
+       return 0;
+}
+
 static struct dev_pm_ops omap_hsmmc_dev_pm_ops = {
        .suspend        = omap_hsmmc_suspend,
        .resume         = omap_hsmmc_resume,
+       .runtime_suspend = omap_hsmmc_runtime_suspend,
+       .runtime_resume = omap_hsmmc_runtime_resume,
 };
 
 static struct platform_driver omap_hsmmc_driver = {