Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Balaji T K and committed by
Chris Ball
fa4aa2d4 7a8c2cef

+56 -55
+56 -55
drivers/mmc/host/omap_hsmmc.c
··· 33 33 #include <linux/semaphore.h> 34 34 #include <linux/gpio.h> 35 35 #include <linux/regulator/consumer.h> 36 + #include <linux/pm_runtime.h> 36 37 #include <plat/dma.h> 37 38 #include <mach/hardware.h> 38 39 #include <plat/board.h> ··· 117 116 #define OMAP_MMC4_DEVID 3 118 117 #define OMAP_MMC5_DEVID 4 119 118 119 + #define MMC_AUTOSUSPEND_DELAY 100 120 120 #define MMC_TIMEOUT_MS 20 121 121 #define OMAP_MMC_MASTER_CLOCK 96000000 122 122 #define DRIVER_NAME "omap_hsmmc" ··· 1158 1156 int ret; 1159 1157 1160 1158 /* Disable the clocks */ 1161 - clk_disable(host->fclk); 1162 - clk_disable(host->iclk); 1159 + pm_runtime_put_sync(host->dev); 1163 1160 if (host->got_dbclk) 1164 1161 clk_disable(host->dbclk); 1165 1162 ··· 1169 1168 if (!ret) 1170 1169 ret = mmc_slot(host).set_power(host->dev, host->slot_id, 1, 1171 1170 vdd); 1172 - clk_enable(host->iclk); 1173 - clk_enable(host->fclk); 1171 + pm_runtime_get_sync(host->dev); 1174 1172 if (host->got_dbclk) 1175 1173 clk_enable(host->dbclk); 1176 1174 ··· 1605 1605 u32 con; 1606 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 1610 if (ios->power_mode != host->power_mode) { 1611 1611 switch (ios->power_mode) { ··· 1700 1700 else 1701 1701 OMAP_HSMMC_WRITE(host->base, CON, con & ~OD); 1702 1702 1703 - if (host->power_mode == MMC_POWER_OFF) 1704 - mmc_host_disable(host->mmc); 1703 + pm_runtime_put_autosuspend(host->dev); 1705 1704 } 1706 1705 1707 1706 static int omap_hsmmc_get_cd(struct mmc_host *mmc) ··· 1759 1760 static int omap_hsmmc_enable_fclk(struct mmc_host *mmc) 1760 1761 { 1761 1762 struct omap_hsmmc_host *host = mmc_priv(mmc); 1762 - int err; 1763 1763 1764 - err = clk_enable(host->fclk); 1765 - if (err) 1766 - return err; 1767 - dev_dbg(mmc_dev(host->mmc), "mmc_fclk: enabled\n"); 1768 - omap_hsmmc_context_restore(host); 1764 + pm_runtime_get_sync(host->dev); 1765 + 1769 1766 return 0; 1770 1767 } 1771 1768 ··· 1769 1774 { 1770 1775 struct omap_hsmmc_host *host = mmc_priv(mmc); 1771 1776 1772 - omap_hsmmc_context_save(host); 1773 - clk_disable(host->fclk); 1774 - dev_dbg(mmc_dev(host->mmc), "mmc_fclk: disabled\n"); 1777 + pm_runtime_mark_last_busy(host->dev); 1778 + pm_runtime_put_autosuspend(host->dev); 1779 + 1775 1780 return 0; 1776 1781 } 1777 1782 ··· 1814 1819 return 0; 1815 1820 } 1816 1821 1817 - if (clk_enable(host->fclk) != 0) { 1818 - seq_printf(s, "can't read the regs\n"); 1819 - return 0; 1820 - } 1822 + pm_runtime_get_sync(host->dev); 1821 1823 1822 1824 seq_printf(s, "SYSCONFIG:\t0x%08x\n", 1823 1825 OMAP_HSMMC_READ(host->base, SYSCONFIG)); ··· 1831 1839 seq_printf(s, "CAPA:\t\t0x%08x\n", 1832 1840 OMAP_HSMMC_READ(host->base, CAPA)); 1833 1841 1834 - clk_disable(host->fclk); 1842 + pm_runtime_mark_last_busy(host->dev); 1843 + pm_runtime_put_autosuspend(host->dev); 1835 1844 1836 1845 return 0; 1837 1846 } ··· 1953 1960 1954 1961 mmc->caps |= MMC_CAP_DISABLE; 1955 1962 1956 - if (clk_enable(host->iclk) != 0) { 1957 - clk_put(host->iclk); 1958 - clk_put(host->fclk); 1959 - goto err1; 1960 - } 1961 - 1962 - if (mmc_host_enable(host->mmc) != 0) { 1963 - clk_disable(host->iclk); 1964 - clk_put(host->iclk); 1965 - clk_put(host->fclk); 1966 - goto err1; 1967 - } 1963 + pm_runtime_enable(host->dev); 1964 + pm_runtime_get_sync(host->dev); 1965 + pm_runtime_set_autosuspend_delay(host->dev, MMC_AUTOSUSPEND_DELAY); 1966 + pm_runtime_use_autosuspend(host->dev); 1968 1967 1969 1968 if (cpu_is_omap2430()) { 1970 1969 host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck"); ··· 2083 2098 } 2084 2099 2085 2100 omap_hsmmc_debugfs(mmc); 2101 + pm_runtime_mark_last_busy(host->dev); 2102 + pm_runtime_put_autosuspend(host->dev); 2086 2103 2087 2104 return 0; 2088 2105 ··· 2100 2113 err_irq_cd_init: 2101 2114 free_irq(host->irq, host); 2102 2115 err_irq: 2103 - mmc_host_disable(host->mmc); 2104 - clk_disable(host->iclk); 2116 + pm_runtime_mark_last_busy(host->dev); 2117 + pm_runtime_put_autosuspend(host->dev); 2105 2118 clk_put(host->fclk); 2106 2119 clk_put(host->iclk); 2107 2120 if (host->got_dbclk) { ··· 2125 2138 struct resource *res; 2126 2139 2127 2140 if (host) { 2128 - mmc_host_enable(host->mmc); 2141 + pm_runtime_get_sync(host->dev); 2129 2142 mmc_remove_host(host->mmc); 2130 2143 if (host->use_reg) 2131 2144 omap_hsmmc_reg_put(host); ··· 2136 2149 free_irq(mmc_slot(host).card_detect_irq, host); 2137 2150 flush_work_sync(&host->mmc_carddetect_work); 2138 2151 2139 - mmc_host_disable(host->mmc); 2140 - clk_disable(host->iclk); 2152 + pm_runtime_put_sync(host->dev); 2153 + pm_runtime_disable(host->dev); 2141 2154 clk_put(host->fclk); 2142 2155 clk_put(host->iclk); 2143 2156 if (host->got_dbclk) { ··· 2169 2182 return 0; 2170 2183 2171 2184 if (host) { 2185 + pm_runtime_get_sync(host->dev); 2172 2186 host->suspended = 1; 2173 2187 if (host->pdata->suspend) { 2174 2188 ret = host->pdata->suspend(&pdev->dev, ··· 2184 2196 } 2185 2197 cancel_work_sync(&host->mmc_carddetect_work); 2186 2198 ret = mmc_suspend_host(host->mmc); 2187 - mmc_host_enable(host->mmc); 2199 + 2188 2200 if (ret == 0) { 2189 2201 omap_hsmmc_disable_irq(host); 2190 2202 OMAP_HSMMC_WRITE(host->base, HCTL, 2191 2203 OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP); 2192 - mmc_host_disable(host->mmc); 2193 - clk_disable(host->iclk); 2194 2204 if (host->got_dbclk) 2195 2205 clk_disable(host->dbclk); 2196 2206 } else { ··· 2200 2214 dev_dbg(mmc_dev(host->mmc), 2201 2215 "Unmask interrupt failed\n"); 2202 2216 } 2203 - mmc_host_disable(host->mmc); 2204 2217 } 2205 - 2218 + pm_runtime_put_sync(host->dev); 2206 2219 } 2207 2220 return ret; 2208 2221 } ··· 2217 2232 return 0; 2218 2233 2219 2234 if (host) { 2220 - ret = clk_enable(host->iclk); 2221 - if (ret) 2222 - goto clk_en_err; 2223 - 2224 - if (mmc_host_enable(host->mmc) != 0) { 2225 - clk_disable(host->iclk); 2226 - goto clk_en_err; 2227 - } 2235 + pm_runtime_get_sync(host->dev); 2228 2236 2229 2237 if (host->got_dbclk) 2230 2238 clk_enable(host->dbclk); ··· 2237 2259 ret = mmc_resume_host(host->mmc); 2238 2260 if (ret == 0) 2239 2261 host->suspended = 0; 2262 + 2263 + pm_runtime_mark_last_busy(host->dev); 2264 + pm_runtime_put_autosuspend(host->dev); 2240 2265 } 2241 2266 2242 2267 return ret; 2243 2268 2244 - clk_en_err: 2245 - dev_dbg(mmc_dev(host->mmc), 2246 - "Failed to enable MMC clocks during resume\n"); 2247 - return ret; 2248 2269 } 2249 2270 2250 2271 #else ··· 2251 2274 #define omap_hsmmc_resume NULL 2252 2275 #endif 2253 2276 2277 + static int omap_hsmmc_runtime_suspend(struct device *dev) 2278 + { 2279 + struct omap_hsmmc_host *host; 2280 + 2281 + host = platform_get_drvdata(to_platform_device(dev)); 2282 + omap_hsmmc_context_save(host); 2283 + dev_dbg(mmc_dev(host->mmc), "disabled\n"); 2284 + 2285 + return 0; 2286 + } 2287 + 2288 + static int omap_hsmmc_runtime_resume(struct device *dev) 2289 + { 2290 + struct omap_hsmmc_host *host; 2291 + 2292 + host = platform_get_drvdata(to_platform_device(dev)); 2293 + omap_hsmmc_context_restore(host); 2294 + dev_dbg(mmc_dev(host->mmc), "enabled\n"); 2295 + 2296 + return 0; 2297 + } 2298 + 2254 2299 static struct dev_pm_ops omap_hsmmc_dev_pm_ops = { 2255 2300 .suspend = omap_hsmmc_suspend, 2256 2301 .resume = omap_hsmmc_resume, 2302 + .runtime_suspend = omap_hsmmc_runtime_suspend, 2303 + .runtime_resume = omap_hsmmc_runtime_resume, 2257 2304 }; 2258 2305 2259 2306 static struct platform_driver omap_hsmmc_driver = {