|
@@ -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 @@
|
|
#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)
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
/* Disable the clocks */
|
|
/* Disable the clocks */
|
|
- clk_disable(host->fclk);
|
|
|
|
- clk_disable(host->iclk);
|
|
|
|
|
|
+ pm_runtime_put_sync(host->dev);
|
|
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)
|
|
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);
|
|
|
|
- clk_enable(host->fclk);
|
|
|
|
|
|
+ pm_runtime_get_sync(host->dev);
|
|
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)
|
|
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)
|
|
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)
|
|
|
|
- mmc_host_disable(host->mmc);
|
|
|
|
|
|
+ pm_runtime_put_autosuspend(host->dev);
|
|
}
|
|
}
|
|
|
|
|
|
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)
|
|
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);
|
|
|
|
- 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;
|
|
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);
|
|
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;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -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) {
|
|
|
|
- seq_printf(s, "can't read the regs\n");
|
|
|
|
- return 0;
|
|
|
|
- }
|
|
|
|
|
|
+ pm_runtime_get_sync(host->dev);
|
|
|
|
|
|
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)
|
|
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)
|
|
|
|
|
|
mmc->caps |= MMC_CAP_DISABLE;
|
|
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()) {
|
|
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)
|
|
}
|
|
}
|
|
|
|
|
|
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 @@ err_reg:
|
|
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);
|
|
|
|
- clk_disable(host->iclk);
|
|
|
|
|
|
+ pm_runtime_mark_last_busy(host->dev);
|
|
|
|
+ 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)
|
|
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)
|
|
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);
|
|
|
|
- clk_disable(host->iclk);
|
|
|
|
|
|
+ pm_runtime_put_sync(host->dev);
|
|
|
|
+ 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)
|
|
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)
|
|
}
|
|
}
|
|
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)
|
|
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)
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
if (host) {
|
|
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)
|
|
if (host->got_dbclk)
|
|
clk_enable(host->dbclk);
|
|
clk_enable(host->dbclk);
|
|
@@ -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 @@ clk_en_err:
|
|
#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 = {
|