diff options
Diffstat (limited to 'drivers/mmc/host/omap_hsmmc.c')
-rw-r--r-- | drivers/mmc/host/omap_hsmmc.c | 246 |
1 files changed, 2 insertions, 244 deletions
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index b0c69104c863..c7de6d62b943 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c | |||
@@ -120,11 +120,6 @@ | |||
120 | #define OMAP_MMC_MASTER_CLOCK 96000000 | 120 | #define OMAP_MMC_MASTER_CLOCK 96000000 |
121 | #define DRIVER_NAME "omap_hsmmc" | 121 | #define DRIVER_NAME "omap_hsmmc" |
122 | 122 | ||
123 | /* Timeouts for entering power saving states on inactivity, msec */ | ||
124 | #define OMAP_MMC_DISABLED_TIMEOUT 100 | ||
125 | #define OMAP_MMC_SLEEP_TIMEOUT 1000 | ||
126 | #define OMAP_MMC_OFF_TIMEOUT 8000 | ||
127 | |||
128 | /* | 123 | /* |
129 | * One controller can have multiple slots, like on some omap boards using | 124 | * One controller can have multiple slots, like on some omap boards using |
130 | * omap.c controller driver. Luckily this is not currently done on any known | 125 | * omap.c controller driver. Luckily this is not currently done on any known |
@@ -1707,8 +1702,6 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
1707 | 1702 | ||
1708 | if (host->power_mode == MMC_POWER_OFF) | 1703 | if (host->power_mode == MMC_POWER_OFF) |
1709 | mmc_host_disable(host->mmc); | 1704 | mmc_host_disable(host->mmc); |
1710 | else | ||
1711 | mmc_host_lazy_disable(host->mmc); | ||
1712 | } | 1705 | } |
1713 | 1706 | ||
1714 | static int omap_hsmmc_get_cd(struct mmc_host *mmc) | 1707 | static int omap_hsmmc_get_cd(struct mmc_host *mmc) |
@@ -1764,220 +1757,6 @@ static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host) | |||
1764 | set_sd_bus_power(host); | 1757 | set_sd_bus_power(host); |
1765 | } | 1758 | } |
1766 | 1759 | ||
1767 | /* | ||
1768 | * Dynamic power saving handling, FSM: | ||
1769 | * ENABLED -> DISABLED -> CARDSLEEP / REGSLEEP -> OFF | ||
1770 | * ^___________| | | | ||
1771 | * |______________________|______________________| | ||
1772 | * | ||
1773 | * ENABLED: mmc host is fully functional | ||
1774 | * DISABLED: fclk is off | ||
1775 | * CARDSLEEP: fclk is off, card is asleep, voltage regulator is asleep | ||
1776 | * REGSLEEP: fclk is off, voltage regulator is asleep | ||
1777 | * OFF: fclk is off, voltage regulator is off | ||
1778 | * | ||
1779 | * Transition handlers return the timeout for the next state transition | ||
1780 | * or negative error. | ||
1781 | */ | ||
1782 | |||
1783 | enum {ENABLED = 0, DISABLED, CARDSLEEP, REGSLEEP, OFF}; | ||
1784 | |||
1785 | /* Handler for [ENABLED -> DISABLED] transition */ | ||
1786 | static int omap_hsmmc_enabled_to_disabled(struct omap_hsmmc_host *host) | ||
1787 | { | ||
1788 | omap_hsmmc_context_save(host); | ||
1789 | clk_disable(host->fclk); | ||
1790 | host->dpm_state = DISABLED; | ||
1791 | |||
1792 | dev_dbg(mmc_dev(host->mmc), "ENABLED -> DISABLED\n"); | ||
1793 | |||
1794 | if (host->power_mode == MMC_POWER_OFF) | ||
1795 | return 0; | ||
1796 | |||
1797 | return OMAP_MMC_SLEEP_TIMEOUT; | ||
1798 | } | ||
1799 | |||
1800 | /* Handler for [DISABLED -> REGSLEEP / CARDSLEEP] transition */ | ||
1801 | static int omap_hsmmc_disabled_to_sleep(struct omap_hsmmc_host *host) | ||
1802 | { | ||
1803 | int err, new_state; | ||
1804 | |||
1805 | if (!mmc_try_claim_host(host->mmc)) | ||
1806 | return 0; | ||
1807 | |||
1808 | clk_enable(host->fclk); | ||
1809 | omap_hsmmc_context_restore(host); | ||
1810 | if (mmc_card_can_sleep(host->mmc)) { | ||
1811 | err = mmc_card_sleep(host->mmc); | ||
1812 | if (err < 0) { | ||
1813 | clk_disable(host->fclk); | ||
1814 | mmc_release_host(host->mmc); | ||
1815 | return err; | ||
1816 | } | ||
1817 | new_state = CARDSLEEP; | ||
1818 | } else { | ||
1819 | new_state = REGSLEEP; | ||
1820 | } | ||
1821 | if (mmc_slot(host).set_sleep) | ||
1822 | mmc_slot(host).set_sleep(host->dev, host->slot_id, 1, 0, | ||
1823 | new_state == CARDSLEEP); | ||
1824 | /* FIXME: turn off bus power and perhaps interrupts too */ | ||
1825 | clk_disable(host->fclk); | ||
1826 | host->dpm_state = new_state; | ||
1827 | |||
1828 | mmc_release_host(host->mmc); | ||
1829 | |||
1830 | dev_dbg(mmc_dev(host->mmc), "DISABLED -> %s\n", | ||
1831 | host->dpm_state == CARDSLEEP ? "CARDSLEEP" : "REGSLEEP"); | ||
1832 | |||
1833 | if (mmc_slot(host).no_off) | ||
1834 | return 0; | ||
1835 | |||
1836 | if ((host->mmc->caps & MMC_CAP_NONREMOVABLE) || | ||
1837 | mmc_slot(host).card_detect || | ||
1838 | (mmc_slot(host).get_cover_state && | ||
1839 | mmc_slot(host).get_cover_state(host->dev, host->slot_id))) | ||
1840 | return OMAP_MMC_OFF_TIMEOUT; | ||
1841 | |||
1842 | return 0; | ||
1843 | } | ||
1844 | |||
1845 | /* Handler for [REGSLEEP / CARDSLEEP -> OFF] transition */ | ||
1846 | static int omap_hsmmc_sleep_to_off(struct omap_hsmmc_host *host) | ||
1847 | { | ||
1848 | if (!mmc_try_claim_host(host->mmc)) | ||
1849 | return 0; | ||
1850 | |||
1851 | if (mmc_slot(host).no_off) | ||
1852 | return 0; | ||
1853 | |||
1854 | if (!((host->mmc->caps & MMC_CAP_NONREMOVABLE) || | ||
1855 | mmc_slot(host).card_detect || | ||
1856 | (mmc_slot(host).get_cover_state && | ||
1857 | mmc_slot(host).get_cover_state(host->dev, host->slot_id)))) { | ||
1858 | mmc_release_host(host->mmc); | ||
1859 | return 0; | ||
1860 | } | ||
1861 | |||
1862 | mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0); | ||
1863 | host->vdd = 0; | ||
1864 | host->power_mode = MMC_POWER_OFF; | ||
1865 | |||
1866 | dev_dbg(mmc_dev(host->mmc), "%s -> OFF\n", | ||
1867 | host->dpm_state == CARDSLEEP ? "CARDSLEEP" : "REGSLEEP"); | ||
1868 | |||
1869 | host->dpm_state = OFF; | ||
1870 | |||
1871 | mmc_release_host(host->mmc); | ||
1872 | |||
1873 | return 0; | ||
1874 | } | ||
1875 | |||
1876 | /* Handler for [DISABLED -> ENABLED] transition */ | ||
1877 | static int omap_hsmmc_disabled_to_enabled(struct omap_hsmmc_host *host) | ||
1878 | { | ||
1879 | int err; | ||
1880 | |||
1881 | err = clk_enable(host->fclk); | ||
1882 | if (err < 0) | ||
1883 | return err; | ||
1884 | |||
1885 | omap_hsmmc_context_restore(host); | ||
1886 | host->dpm_state = ENABLED; | ||
1887 | |||
1888 | dev_dbg(mmc_dev(host->mmc), "DISABLED -> ENABLED\n"); | ||
1889 | |||
1890 | return 0; | ||
1891 | } | ||
1892 | |||
1893 | /* Handler for [SLEEP -> ENABLED] transition */ | ||
1894 | static int omap_hsmmc_sleep_to_enabled(struct omap_hsmmc_host *host) | ||
1895 | { | ||
1896 | if (!mmc_try_claim_host(host->mmc)) | ||
1897 | return 0; | ||
1898 | |||
1899 | clk_enable(host->fclk); | ||
1900 | omap_hsmmc_context_restore(host); | ||
1901 | if (mmc_slot(host).set_sleep) | ||
1902 | mmc_slot(host).set_sleep(host->dev, host->slot_id, 0, | ||
1903 | host->vdd, host->dpm_state == CARDSLEEP); | ||
1904 | if (mmc_card_can_sleep(host->mmc)) | ||
1905 | mmc_card_awake(host->mmc); | ||
1906 | |||
1907 | dev_dbg(mmc_dev(host->mmc), "%s -> ENABLED\n", | ||
1908 | host->dpm_state == CARDSLEEP ? "CARDSLEEP" : "REGSLEEP"); | ||
1909 | |||
1910 | host->dpm_state = ENABLED; | ||
1911 | |||
1912 | mmc_release_host(host->mmc); | ||
1913 | |||
1914 | return 0; | ||
1915 | } | ||
1916 | |||
1917 | /* Handler for [OFF -> ENABLED] transition */ | ||
1918 | static int omap_hsmmc_off_to_enabled(struct omap_hsmmc_host *host) | ||
1919 | { | ||
1920 | clk_enable(host->fclk); | ||
1921 | |||
1922 | omap_hsmmc_context_restore(host); | ||
1923 | omap_hsmmc_conf_bus_power(host); | ||
1924 | mmc_power_restore_host(host->mmc); | ||
1925 | |||
1926 | host->dpm_state = ENABLED; | ||
1927 | |||
1928 | dev_dbg(mmc_dev(host->mmc), "OFF -> ENABLED\n"); | ||
1929 | |||
1930 | return 0; | ||
1931 | } | ||
1932 | |||
1933 | /* | ||
1934 | * Bring MMC host to ENABLED from any other PM state. | ||
1935 | */ | ||
1936 | static int omap_hsmmc_enable(struct mmc_host *mmc) | ||
1937 | { | ||
1938 | struct omap_hsmmc_host *host = mmc_priv(mmc); | ||
1939 | |||
1940 | switch (host->dpm_state) { | ||
1941 | case DISABLED: | ||
1942 | return omap_hsmmc_disabled_to_enabled(host); | ||
1943 | case CARDSLEEP: | ||
1944 | case REGSLEEP: | ||
1945 | return omap_hsmmc_sleep_to_enabled(host); | ||
1946 | case OFF: | ||
1947 | return omap_hsmmc_off_to_enabled(host); | ||
1948 | default: | ||
1949 | dev_dbg(mmc_dev(host->mmc), "UNKNOWN state\n"); | ||
1950 | return -EINVAL; | ||
1951 | } | ||
1952 | } | ||
1953 | |||
1954 | /* | ||
1955 | * Bring MMC host in PM state (one level deeper). | ||
1956 | */ | ||
1957 | static int omap_hsmmc_disable(struct mmc_host *mmc, int lazy) | ||
1958 | { | ||
1959 | struct omap_hsmmc_host *host = mmc_priv(mmc); | ||
1960 | |||
1961 | switch (host->dpm_state) { | ||
1962 | case ENABLED: { | ||
1963 | int delay; | ||
1964 | |||
1965 | delay = omap_hsmmc_enabled_to_disabled(host); | ||
1966 | if (lazy || delay < 0) | ||
1967 | return delay; | ||
1968 | return 0; | ||
1969 | } | ||
1970 | case DISABLED: | ||
1971 | return omap_hsmmc_disabled_to_sleep(host); | ||
1972 | case CARDSLEEP: | ||
1973 | case REGSLEEP: | ||
1974 | return omap_hsmmc_sleep_to_off(host); | ||
1975 | default: | ||
1976 | dev_dbg(mmc_dev(host->mmc), "UNKNOWN state\n"); | ||
1977 | return -EINVAL; | ||
1978 | } | ||
1979 | } | ||
1980 | |||
1981 | static int omap_hsmmc_enable_fclk(struct mmc_host *mmc) | 1760 | static int omap_hsmmc_enable_fclk(struct mmc_host *mmc) |
1982 | { | 1761 | { |
1983 | struct omap_hsmmc_host *host = mmc_priv(mmc); | 1762 | struct omap_hsmmc_host *host = mmc_priv(mmc); |
@@ -2014,17 +1793,6 @@ static const struct mmc_host_ops omap_hsmmc_ops = { | |||
2014 | /* NYET -- enable_sdio_irq */ | 1793 | /* NYET -- enable_sdio_irq */ |
2015 | }; | 1794 | }; |
2016 | 1795 | ||
2017 | static const struct mmc_host_ops omap_hsmmc_ps_ops = { | ||
2018 | .enable = omap_hsmmc_enable, | ||
2019 | .disable = omap_hsmmc_disable, | ||
2020 | .request = omap_hsmmc_request, | ||
2021 | .set_ios = omap_hsmmc_set_ios, | ||
2022 | .get_cd = omap_hsmmc_get_cd, | ||
2023 | .get_ro = omap_hsmmc_get_ro, | ||
2024 | .init_card = omap_hsmmc_init_card, | ||
2025 | /* NYET -- enable_sdio_irq */ | ||
2026 | }; | ||
2027 | |||
2028 | #ifdef CONFIG_DEBUG_FS | 1796 | #ifdef CONFIG_DEBUG_FS |
2029 | 1797 | ||
2030 | static int omap_hsmmc_regs_show(struct seq_file *s, void *data) | 1798 | static int omap_hsmmc_regs_show(struct seq_file *s, void *data) |
@@ -2046,7 +1814,7 @@ static int omap_hsmmc_regs_show(struct seq_file *s, void *data) | |||
2046 | host->dpm_state, mmc->nesting_cnt, | 1814 | host->dpm_state, mmc->nesting_cnt, |
2047 | host->context_loss, context_loss); | 1815 | host->context_loss, context_loss); |
2048 | 1816 | ||
2049 | if (host->suspended || host->dpm_state == OFF) { | 1817 | if (host->suspended) { |
2050 | seq_printf(s, "host suspended, can't read registers\n"); | 1818 | seq_printf(s, "host suspended, can't read registers\n"); |
2051 | return 0; | 1819 | return 0; |
2052 | } | 1820 | } |
@@ -2160,10 +1928,7 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) | |||
2160 | platform_set_drvdata(pdev, host); | 1928 | platform_set_drvdata(pdev, host); |
2161 | INIT_WORK(&host->mmc_carddetect_work, omap_hsmmc_detect); | 1929 | INIT_WORK(&host->mmc_carddetect_work, omap_hsmmc_detect); |
2162 | 1930 | ||
2163 | if (mmc_slot(host).power_saving) | 1931 | mmc->ops = &omap_hsmmc_ops; |
2164 | mmc->ops = &omap_hsmmc_ps_ops; | ||
2165 | else | ||
2166 | mmc->ops = &omap_hsmmc_ops; | ||
2167 | 1932 | ||
2168 | /* | 1933 | /* |
2169 | * If regulator_disable can only put vcc_aux to sleep then there is | 1934 | * If regulator_disable can only put vcc_aux to sleep then there is |
@@ -2194,9 +1959,6 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) | |||
2194 | omap_hsmmc_context_save(host); | 1959 | omap_hsmmc_context_save(host); |
2195 | 1960 | ||
2196 | mmc->caps |= MMC_CAP_DISABLE; | 1961 | mmc->caps |= MMC_CAP_DISABLE; |
2197 | mmc_set_disable_delay(mmc, OMAP_MMC_DISABLED_TIMEOUT); | ||
2198 | /* we start off in DISABLED state */ | ||
2199 | host->dpm_state = DISABLED; | ||
2200 | 1962 | ||
2201 | if (clk_enable(host->iclk) != 0) { | 1963 | if (clk_enable(host->iclk) != 0) { |
2202 | clk_put(host->iclk); | 1964 | clk_put(host->iclk); |
@@ -2319,8 +2081,6 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) | |||
2319 | 2081 | ||
2320 | omap_hsmmc_disable_irq(host); | 2082 | omap_hsmmc_disable_irq(host); |
2321 | 2083 | ||
2322 | mmc_host_lazy_disable(host->mmc); | ||
2323 | |||
2324 | omap_hsmmc_protect_card(host); | 2084 | omap_hsmmc_protect_card(host); |
2325 | 2085 | ||
2326 | mmc_add_host(mmc); | 2086 | mmc_add_host(mmc); |
@@ -2499,8 +2259,6 @@ static int omap_hsmmc_resume(struct device *dev) | |||
2499 | ret = mmc_resume_host(host->mmc); | 2259 | ret = mmc_resume_host(host->mmc); |
2500 | if (ret == 0) | 2260 | if (ret == 0) |
2501 | host->suspended = 0; | 2261 | host->suspended = 0; |
2502 | |||
2503 | mmc_host_lazy_disable(host->mmc); | ||
2504 | } | 2262 | } |
2505 | 2263 | ||
2506 | return ret; | 2264 | return ret; |