diff options
author | Balaji T K <balajitk@ti.com> | 2011-07-01 22:09:35 +0530 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2011-07-20 17:21:17 -0400 |
commit | fa4aa2d48dabed9d1288d235524cb8d0a8e81c00 (patch) | |
tree | 5aeadac6fca6521d511dd59c5a9917208c9dec64 /drivers/mmc | |
parent | 7a8c2cef3dd6ffc586dfc5e3f63b73b4be2662e7 (diff) | |
download | linux-fa4aa2d48dabed9d1288d235524cb8d0a8e81c00.tar.bz2 |
mmc: omap_hsmmc: add runtime pm support
* 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>
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/host/omap_hsmmc.c | 111 |
1 files changed, 56 insertions, 55 deletions
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index c7de6d62b943..10122b1cc424 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -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> @@ -116,6 +117,7 @@ #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 = { |