aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorBalaji T K <balajitk@ti.com>2011-07-01 12:39:35 -0400
committerChris Ball <cjb@laptop.org>2011-07-20 17:21:17 -0400
commitfa4aa2d48dabed9d1288d235524cb8d0a8e81c00 (patch)
tree5aeadac6fca6521d511dd59c5a9917208c9dec64 /drivers/mmc
parent7a8c2cef3dd6ffc586dfc5e3f63b73b4be2662e7 (diff)
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.c111
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 @@
33#include <linux/semaphore.h> 33#include <linux/semaphore.h>
34#include <linux/gpio.h> 34#include <linux/gpio.h>
35#include <linux/regulator/consumer.h> 35#include <linux/regulator/consumer.h>
36#include <linux/pm_runtime.h>
36#include <plat/dma.h> 37#include <plat/dma.h>
37#include <mach/hardware.h> 38#include <mach/hardware.h>
38#include <plat/board.h> 39#include <plat/board.h>
@@ -116,6 +117,7 @@
116#define OMAP_MMC4_DEVID 3 117#define OMAP_MMC4_DEVID 3
117#define OMAP_MMC5_DEVID 4 118#define OMAP_MMC5_DEVID 4
118 119
120#define MMC_AUTOSUSPEND_DELAY 100
119#define MMC_TIMEOUT_MS 20 121#define MMC_TIMEOUT_MS 20
120#define OMAP_MMC_MASTER_CLOCK 96000000 122#define OMAP_MMC_MASTER_CLOCK 96000000
121#define DRIVER_NAME "omap_hsmmc" 123#define DRIVER_NAME "omap_hsmmc"
@@ -1156,8 +1158,7 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd)
1156 int ret; 1158 int ret;
1157 1159
1158 /* Disable the clocks */ 1160 /* Disable the clocks */
1159 clk_disable(host->fclk); 1161 pm_runtime_put_sync(host->dev);
1160 clk_disable(host->iclk);
1161 if (host->got_dbclk) 1162 if (host->got_dbclk)
1162 clk_disable(host->dbclk); 1163 clk_disable(host->dbclk);
1163 1164
@@ -1168,8 +1169,7 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd)
1168 if (!ret) 1169 if (!ret)
1169 ret = mmc_slot(host).set_power(host->dev, host->slot_id, 1, 1170 ret = mmc_slot(host).set_power(host->dev, host->slot_id, 1,
1170 vdd); 1171 vdd);
1171 clk_enable(host->iclk); 1172 pm_runtime_get_sync(host->dev);
1172 clk_enable(host->fclk);
1173 if (host->got_dbclk) 1173 if (host->got_dbclk)
1174 clk_enable(host->dbclk); 1174 clk_enable(host->dbclk);
1175 1175
@@ -1605,7 +1605,7 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
1605 u32 con; 1605 u32 con;
1606 int do_send_init_stream = 0; 1606 int do_send_init_stream = 0;
1607 1607
1608 mmc_host_enable(host->mmc); 1608 pm_runtime_get_sync(host->dev);
1609 1609
1610 if (ios->power_mode != host->power_mode) { 1610 if (ios->power_mode != host->power_mode) {
1611 switch (ios->power_mode) { 1611 switch (ios->power_mode) {
@@ -1700,8 +1700,7 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
1700 else 1700 else
1701 OMAP_HSMMC_WRITE(host->base, CON, con & ~OD); 1701 OMAP_HSMMC_WRITE(host->base, CON, con & ~OD);
1702 1702
1703 if (host->power_mode == MMC_POWER_OFF) 1703 pm_runtime_put_autosuspend(host->dev);
1704 mmc_host_disable(host->mmc);
1705} 1704}
1706 1705
1707static int omap_hsmmc_get_cd(struct mmc_host *mmc) 1706static 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)
1760static int omap_hsmmc_enable_fclk(struct mmc_host *mmc) 1759static int omap_hsmmc_enable_fclk(struct mmc_host *mmc)
1761{ 1760{
1762 struct omap_hsmmc_host *host = mmc_priv(mmc); 1761 struct omap_hsmmc_host *host = mmc_priv(mmc);
1763 int err;
1764 1762
1765 err = clk_enable(host->fclk); 1763 pm_runtime_get_sync(host->dev);
1766 if (err) 1764
1767 return err;
1768 dev_dbg(mmc_dev(host->mmc), "mmc_fclk: enabled\n");
1769 omap_hsmmc_context_restore(host);
1770 return 0; 1765 return 0;
1771} 1766}
1772 1767
@@ -1774,9 +1769,9 @@ static int omap_hsmmc_disable_fclk(struct mmc_host *mmc, int lazy)
1774{ 1769{
1775 struct omap_hsmmc_host *host = mmc_priv(mmc); 1770 struct omap_hsmmc_host *host = mmc_priv(mmc);
1776 1771
1777 omap_hsmmc_context_save(host); 1772 pm_runtime_mark_last_busy(host->dev);
1778 clk_disable(host->fclk); 1773 pm_runtime_put_autosuspend(host->dev);
1779 dev_dbg(mmc_dev(host->mmc), "mmc_fclk: disabled\n"); 1774
1780 return 0; 1775 return 0;
1781} 1776}
1782 1777
@@ -1819,10 +1814,7 @@ static int omap_hsmmc_regs_show(struct seq_file *s, void *data)
1819 return 0; 1814 return 0;
1820 } 1815 }
1821 1816
1822 if (clk_enable(host->fclk) != 0) { 1817 pm_runtime_get_sync(host->dev);
1823 seq_printf(s, "can't read the regs\n");
1824 return 0;
1825 }
1826 1818
1827 seq_printf(s, "SYSCONFIG:\t0x%08x\n", 1819 seq_printf(s, "SYSCONFIG:\t0x%08x\n",
1828 OMAP_HSMMC_READ(host->base, SYSCONFIG)); 1820 OMAP_HSMMC_READ(host->base, SYSCONFIG));
@@ -1839,7 +1831,8 @@ static int omap_hsmmc_regs_show(struct seq_file *s, void *data)
1839 seq_printf(s, "CAPA:\t\t0x%08x\n", 1831 seq_printf(s, "CAPA:\t\t0x%08x\n",
1840 OMAP_HSMMC_READ(host->base, CAPA)); 1832 OMAP_HSMMC_READ(host->base, CAPA));
1841 1833
1842 clk_disable(host->fclk); 1834 pm_runtime_mark_last_busy(host->dev);
1835 pm_runtime_put_autosuspend(host->dev);
1843 1836
1844 return 0; 1837 return 0;
1845} 1838}
@@ -1960,18 +1953,10 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
1960 1953
1961 mmc->caps |= MMC_CAP_DISABLE; 1954 mmc->caps |= MMC_CAP_DISABLE;
1962 1955
1963 if (clk_enable(host->iclk) != 0) { 1956 pm_runtime_enable(host->dev);
1964 clk_put(host->iclk); 1957 pm_runtime_get_sync(host->dev);
1965 clk_put(host->fclk); 1958 pm_runtime_set_autosuspend_delay(host->dev, MMC_AUTOSUSPEND_DELAY);
1966 goto err1; 1959 pm_runtime_use_autosuspend(host->dev);
1967 }
1968
1969 if (mmc_host_enable(host->mmc) != 0) {
1970 clk_disable(host->iclk);
1971 clk_put(host->iclk);
1972 clk_put(host->fclk);
1973 goto err1;
1974 }
1975 1960
1976 if (cpu_is_omap2430()) { 1961 if (cpu_is_omap2430()) {
1977 host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck"); 1962 host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck");
@@ -2098,6 +2083,8 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
2098 } 2083 }
2099 2084
2100 omap_hsmmc_debugfs(mmc); 2085 omap_hsmmc_debugfs(mmc);
2086 pm_runtime_mark_last_busy(host->dev);
2087 pm_runtime_put_autosuspend(host->dev);
2101 2088
2102 return 0; 2089 return 0;
2103 2090
@@ -2113,8 +2100,8 @@ err_reg:
2113err_irq_cd_init: 2100err_irq_cd_init:
2114 free_irq(host->irq, host); 2101 free_irq(host->irq, host);
2115err_irq: 2102err_irq:
2116 mmc_host_disable(host->mmc); 2103 pm_runtime_mark_last_busy(host->dev);
2117 clk_disable(host->iclk); 2104 pm_runtime_put_autosuspend(host->dev);
2118 clk_put(host->fclk); 2105 clk_put(host->fclk);
2119 clk_put(host->iclk); 2106 clk_put(host->iclk);
2120 if (host->got_dbclk) { 2107 if (host->got_dbclk) {
@@ -2138,7 +2125,7 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
2138 struct resource *res; 2125 struct resource *res;
2139 2126
2140 if (host) { 2127 if (host) {
2141 mmc_host_enable(host->mmc); 2128 pm_runtime_get_sync(host->dev);
2142 mmc_remove_host(host->mmc); 2129 mmc_remove_host(host->mmc);
2143 if (host->use_reg) 2130 if (host->use_reg)
2144 omap_hsmmc_reg_put(host); 2131 omap_hsmmc_reg_put(host);
@@ -2149,8 +2136,8 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
2149 free_irq(mmc_slot(host).card_detect_irq, host); 2136 free_irq(mmc_slot(host).card_detect_irq, host);
2150 flush_work_sync(&host->mmc_carddetect_work); 2137 flush_work_sync(&host->mmc_carddetect_work);
2151 2138
2152 mmc_host_disable(host->mmc); 2139 pm_runtime_put_sync(host->dev);
2153 clk_disable(host->iclk); 2140 pm_runtime_disable(host->dev);
2154 clk_put(host->fclk); 2141 clk_put(host->fclk);
2155 clk_put(host->iclk); 2142 clk_put(host->iclk);
2156 if (host->got_dbclk) { 2143 if (host->got_dbclk) {
@@ -2182,6 +2169,7 @@ static int omap_hsmmc_suspend(struct device *dev)
2182 return 0; 2169 return 0;
2183 2170
2184 if (host) { 2171 if (host) {
2172 pm_runtime_get_sync(host->dev);
2185 host->suspended = 1; 2173 host->suspended = 1;
2186 if (host->pdata->suspend) { 2174 if (host->pdata->suspend) {
2187 ret = host->pdata->suspend(&pdev->dev, 2175 ret = host->pdata->suspend(&pdev->dev,
@@ -2196,13 +2184,11 @@ static int omap_hsmmc_suspend(struct device *dev)
2196 } 2184 }
2197 cancel_work_sync(&host->mmc_carddetect_work); 2185 cancel_work_sync(&host->mmc_carddetect_work);
2198 ret = mmc_suspend_host(host->mmc); 2186 ret = mmc_suspend_host(host->mmc);
2199 mmc_host_enable(host->mmc); 2187
2200 if (ret == 0) { 2188 if (ret == 0) {
2201 omap_hsmmc_disable_irq(host); 2189 omap_hsmmc_disable_irq(host);
2202 OMAP_HSMMC_WRITE(host->base, HCTL, 2190 OMAP_HSMMC_WRITE(host->base, HCTL,
2203 OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP); 2191 OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP);
2204 mmc_host_disable(host->mmc);
2205 clk_disable(host->iclk);
2206 if (host->got_dbclk) 2192 if (host->got_dbclk)
2207 clk_disable(host->dbclk); 2193 clk_disable(host->dbclk);
2208 } else { 2194 } else {
@@ -2214,9 +2200,8 @@ static int omap_hsmmc_suspend(struct device *dev)
2214 dev_dbg(mmc_dev(host->mmc), 2200 dev_dbg(mmc_dev(host->mmc),
2215 "Unmask interrupt failed\n"); 2201 "Unmask interrupt failed\n");
2216 } 2202 }
2217 mmc_host_disable(host->mmc);
2218 } 2203 }
2219 2204 pm_runtime_put_sync(host->dev);
2220 } 2205 }
2221 return ret; 2206 return ret;
2222} 2207}
@@ -2232,14 +2217,7 @@ static int omap_hsmmc_resume(struct device *dev)
2232 return 0; 2217 return 0;
2233 2218
2234 if (host) { 2219 if (host) {
2235 ret = clk_enable(host->iclk); 2220 pm_runtime_get_sync(host->dev);
2236 if (ret)
2237 goto clk_en_err;
2238
2239 if (mmc_host_enable(host->mmc) != 0) {
2240 clk_disable(host->iclk);
2241 goto clk_en_err;
2242 }
2243 2221
2244 if (host->got_dbclk) 2222 if (host->got_dbclk)
2245 clk_enable(host->dbclk); 2223 clk_enable(host->dbclk);
@@ -2259,14 +2237,13 @@ static int omap_hsmmc_resume(struct device *dev)
2259 ret = mmc_resume_host(host->mmc); 2237 ret = mmc_resume_host(host->mmc);
2260 if (ret == 0) 2238 if (ret == 0)
2261 host->suspended = 0; 2239 host->suspended = 0;
2240
2241 pm_runtime_mark_last_busy(host->dev);
2242 pm_runtime_put_autosuspend(host->dev);
2262 } 2243 }
2263 2244
2264 return ret; 2245 return ret;
2265 2246
2266clk_en_err:
2267 dev_dbg(mmc_dev(host->mmc),
2268 "Failed to enable MMC clocks during resume\n");
2269 return ret;
2270} 2247}
2271 2248
2272#else 2249#else
@@ -2274,9 +2251,33 @@ clk_en_err:
2274#define omap_hsmmc_resume NULL 2251#define omap_hsmmc_resume NULL
2275#endif 2252#endif
2276 2253
2254static int omap_hsmmc_runtime_suspend(struct device *dev)
2255{
2256 struct omap_hsmmc_host *host;
2257
2258 host = platform_get_drvdata(to_platform_device(dev));
2259 omap_hsmmc_context_save(host);
2260 dev_dbg(mmc_dev(host->mmc), "disabled\n");
2261
2262 return 0;
2263}
2264
2265static int omap_hsmmc_runtime_resume(struct device *dev)
2266{
2267 struct omap_hsmmc_host *host;
2268
2269 host = platform_get_drvdata(to_platform_device(dev));
2270 omap_hsmmc_context_restore(host);
2271 dev_dbg(mmc_dev(host->mmc), "enabled\n");
2272
2273 return 0;
2274}
2275
2277static struct dev_pm_ops omap_hsmmc_dev_pm_ops = { 2276static struct dev_pm_ops omap_hsmmc_dev_pm_ops = {
2278 .suspend = omap_hsmmc_suspend, 2277 .suspend = omap_hsmmc_suspend,
2279 .resume = omap_hsmmc_resume, 2278 .resume = omap_hsmmc_resume,
2279 .runtime_suspend = omap_hsmmc_runtime_suspend,
2280 .runtime_resume = omap_hsmmc_runtime_resume,
2280}; 2281};
2281 2282
2282static struct platform_driver omap_hsmmc_driver = { 2283static struct platform_driver omap_hsmmc_driver = {