aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hansson <ulf.hansson@linaro.org>2012-05-09 10:15:26 -0400
committerChris Ball <cjb@laptop.org>2012-05-09 12:55:01 -0400
commitfa5501890d8974301042e0202d342a6cbe8609f4 (patch)
treeae127577d2591e22eed2621d87d1b289e016f3f6
parent95dcc2cb6c9c84555c29187f8b7cf39e83991a29 (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>
-rw-r--r--drivers/mmc/core/core.c18
1 files changed, 15 insertions, 3 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index ba821fe70bc..0b6141d29db 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
44static struct workqueue_struct *workqueue; 44static struct workqueue_struct *workqueue;
45static 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)
1199void mmc_power_off(struct mmc_host *host) 1203void 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
2006void mmc_rescan(struct work_struct *work) 2014void 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
2064void mmc_start_host(struct mmc_host *host) 2075void 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