diff options
author | Ulf Hansson <ulf.hansson@linaro.org> | 2012-05-09 10:15:26 -0400 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2012-05-09 12:55:01 -0400 |
commit | fa5501890d8974301042e0202d342a6cbe8609f4 (patch) | |
tree | ae127577d2591e22eed2621d87d1b289e016f3f6 /drivers/mmc | |
parent | 95dcc2cb6c9c84555c29187f8b7cf39e83991a29 (diff) |
mmc: core: Prevent eMMC VCC supply to be cut from late init
For eMMC cards that has been initialized from a bootloader,
the VCC voltage supply must not be cut in an uncontrolled
manner, without first sending SLEEP or POWEROFF_NOTIFY.
The regulator_init_complete late initcall, may cut the VCC
regulator if it's reference counter is zero. To be able to
prevent the regulator from being cut, mmc_start_host, which
should execute at device init and thus before late init,
calls mmc_power_up. Then the host driver is able to increase
the reference to the regulator.
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Reviewed-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/core/core.c | 18 |
1 files changed, 15 insertions, 3 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index ba821fe70bca..0b6141d29dbd 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c | |||
@@ -42,6 +42,7 @@ | |||
42 | #include "sdio_ops.h" | 42 | #include "sdio_ops.h" |
43 | 43 | ||
44 | static struct workqueue_struct *workqueue; | 44 | static struct workqueue_struct *workqueue; |
45 | static const unsigned freqs[] = { 400000, 300000, 200000, 100000 }; | ||
45 | 46 | ||
46 | /* | 47 | /* |
47 | * Enabling software CRCs on the data blocks can be a significant (30%) | 48 | * Enabling software CRCs on the data blocks can be a significant (30%) |
@@ -1157,6 +1158,9 @@ static void mmc_power_up(struct mmc_host *host) | |||
1157 | { | 1158 | { |
1158 | int bit; | 1159 | int bit; |
1159 | 1160 | ||
1161 | if (host->ios.power_mode == MMC_POWER_ON) | ||
1162 | return; | ||
1163 | |||
1160 | mmc_host_clk_hold(host); | 1164 | mmc_host_clk_hold(host); |
1161 | 1165 | ||
1162 | /* If ocr is set, we use it */ | 1166 | /* If ocr is set, we use it */ |
@@ -1199,6 +1203,10 @@ static void mmc_power_up(struct mmc_host *host) | |||
1199 | void mmc_power_off(struct mmc_host *host) | 1203 | void mmc_power_off(struct mmc_host *host) |
1200 | { | 1204 | { |
1201 | int err = 0; | 1205 | int err = 0; |
1206 | |||
1207 | if (host->ios.power_mode == MMC_POWER_OFF) | ||
1208 | return; | ||
1209 | |||
1202 | mmc_host_clk_hold(host); | 1210 | mmc_host_clk_hold(host); |
1203 | 1211 | ||
1204 | host->ios.clock = 0; | 1212 | host->ios.clock = 0; |
@@ -2005,7 +2013,6 @@ EXPORT_SYMBOL(mmc_detect_card_removed); | |||
2005 | 2013 | ||
2006 | void mmc_rescan(struct work_struct *work) | 2014 | void mmc_rescan(struct work_struct *work) |
2007 | { | 2015 | { |
2008 | static const unsigned freqs[] = { 400000, 300000, 200000, 100000 }; | ||
2009 | struct mmc_host *host = | 2016 | struct mmc_host *host = |
2010 | container_of(work, struct mmc_host, detect.work); | 2017 | container_of(work, struct mmc_host, detect.work); |
2011 | int i; | 2018 | int i; |
@@ -2044,8 +2051,12 @@ void mmc_rescan(struct work_struct *work) | |||
2044 | */ | 2051 | */ |
2045 | mmc_bus_put(host); | 2052 | mmc_bus_put(host); |
2046 | 2053 | ||
2047 | if (host->ops->get_cd && host->ops->get_cd(host) == 0) | 2054 | if (host->ops->get_cd && host->ops->get_cd(host) == 0) { |
2055 | mmc_claim_host(host); | ||
2056 | mmc_power_off(host); | ||
2057 | mmc_release_host(host); | ||
2048 | goto out; | 2058 | goto out; |
2059 | } | ||
2049 | 2060 | ||
2050 | mmc_claim_host(host); | 2061 | mmc_claim_host(host); |
2051 | for (i = 0; i < ARRAY_SIZE(freqs); i++) { | 2062 | for (i = 0; i < ARRAY_SIZE(freqs); i++) { |
@@ -2063,7 +2074,8 @@ void mmc_rescan(struct work_struct *work) | |||
2063 | 2074 | ||
2064 | void mmc_start_host(struct mmc_host *host) | 2075 | void mmc_start_host(struct mmc_host *host) |
2065 | { | 2076 | { |
2066 | mmc_power_off(host); | 2077 | host->f_init = max(freqs[0], host->f_min); |
2078 | mmc_power_up(host); | ||
2067 | mmc_detect_change(host, 0); | 2079 | mmc_detect_change(host, 0); |
2068 | } | 2080 | } |
2069 | 2081 | ||