Commit fa4aa2d4 authored by Balaji T K's avatar Balaji T K Committed by Chris Ball

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