aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorAdrian Hunter <adrian.hunter@nokia.com>2009-09-22 19:44:51 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-09-23 10:39:35 -0400
commit623821f71bb40f9972630eb1f779817d462ef0ee (patch)
treef4f2680df5db7025fc5bee98792c57cb700e48fb /drivers/mmc
parent9b7c18e070d59ba0acfdb936fd613dfa1d2a4e7d (diff)
omap_hsmmc: put MMC regulator to sleep
When a card is not in use, the voltage regulator can be put to sleep. This is an alternative to powering the card off, when powering off is not safe because the card might be replaced without the driver being aware of it. That situation happens if: - the card is removable i.e. not eMMC - and there is no card detect - and there is a cover switch but the cover is open Signed-off-by: Adrian Hunter <adrian.hunter@nokia.com> Acked-by: Matt Fleming <matt@console-pimps.org> Cc: Ian Molton <ian@mnementh.co.uk> Cc: "Roberto A. Foglietta" <roberto.foglietta@gmail.com> Cc: Jarkko Lavinen <jarkko.lavinen@nokia.com> Cc: Denis Karpov <ext-denis.2.karpov@nokia.com> Cc: Pierre Ossman <pierre@ossman.eu> Cc: Philip Langdale <philipl@overt.org> Cc: "Madhusudhan" <madhu.cr@ti.com> Cc: <linux-mmc@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/host/omap_hsmmc.c59
1 files changed, 54 insertions, 5 deletions
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 016914c2c4e7..c82ec7f4e1a7 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -162,6 +162,7 @@ struct mmc_omap_host {
162 int response_busy; 162 int response_busy;
163 int context_loss; 163 int context_loss;
164 int dpm_state; 164 int dpm_state;
165 int vdd;
165 166
166 struct omap_mmc_platform_data *pdata; 167 struct omap_mmc_platform_data *pdata;
167}; 168};
@@ -1038,10 +1039,12 @@ static void omap_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
1038 case MMC_POWER_OFF: 1039 case MMC_POWER_OFF:
1039 mmc_slot(host).set_power(host->dev, host->slot_id, 1040 mmc_slot(host).set_power(host->dev, host->slot_id,
1040 0, 0); 1041 0, 0);
1042 host->vdd = 0;
1041 break; 1043 break;
1042 case MMC_POWER_UP: 1044 case MMC_POWER_UP:
1043 mmc_slot(host).set_power(host->dev, host->slot_id, 1045 mmc_slot(host).set_power(host->dev, host->slot_id,
1044 1, ios->vdd); 1046 1, ios->vdd);
1047 host->vdd = ios->vdd;
1045 break; 1048 break;
1046 case MMC_POWER_ON: 1049 case MMC_POWER_ON:
1047 do_send_init_stream = 1; 1050 do_send_init_stream = 1;
@@ -1179,19 +1182,20 @@ static void omap_hsmmc_init(struct mmc_omap_host *host)
1179 1182
1180/* 1183/*
1181 * Dynamic power saving handling, FSM: 1184 * Dynamic power saving handling, FSM:
1182 * ENABLED -> DISABLED -> OFF 1185 * ENABLED -> DISABLED -> OFF / REGSLEEP
1183 * ^___________| | 1186 * ^___________| |
1184 * |______________________| 1187 * |______________________|
1185 * 1188 *
1186 * ENABLED: mmc host is fully functional 1189 * ENABLED: mmc host is fully functional
1187 * DISABLED: fclk is off 1190 * DISABLED: fclk is off
1188 * OFF: fclk is off,voltage regulator is off 1191 * OFF: fclk is off,voltage regulator is off
1192 * REGSLEEP: fclk is off,voltage regulator is asleep
1189 * 1193 *
1190 * Transition handlers return the timeout for the next state transition 1194 * Transition handlers return the timeout for the next state transition
1191 * or negative error. 1195 * or negative error.
1192 */ 1196 */
1193 1197
1194enum {ENABLED = 0, DISABLED, OFF}; 1198enum {ENABLED = 0, DISABLED, REGSLEEP, OFF};
1195 1199
1196/* Handler for [ENABLED -> DISABLED] transition */ 1200/* Handler for [ENABLED -> DISABLED] transition */
1197static int omap_mmc_enabled_to_disabled(struct mmc_omap_host *host) 1201static int omap_mmc_enabled_to_disabled(struct mmc_omap_host *host)
@@ -1228,8 +1232,12 @@ static int omap_mmc_disabled_to_off(struct mmc_omap_host *host)
1228 mmc_slot(host).get_cover_state(host->dev, host->slot_id))) { 1232 mmc_slot(host).get_cover_state(host->dev, host->slot_id))) {
1229 mmc_power_save_host(host->mmc); 1233 mmc_power_save_host(host->mmc);
1230 new_state = OFF; 1234 new_state = OFF;
1231 } else 1235 } else {
1232 new_state = DISABLED; 1236 if (mmc_slot(host).set_sleep)
1237 mmc_slot(host).set_sleep(host->dev, host->slot_id,
1238 1, 0, 0);
1239 new_state = REGSLEEP;
1240 }
1233 1241
1234 OMAP_HSMMC_WRITE(host->base, ISE, 0); 1242 OMAP_HSMMC_WRITE(host->base, ISE, 0);
1235 OMAP_HSMMC_WRITE(host->base, IE, 0); 1243 OMAP_HSMMC_WRITE(host->base, IE, 0);
@@ -1286,6 +1294,44 @@ static int omap_mmc_off_to_enabled(struct mmc_omap_host *host)
1286 return 0; 1294 return 0;
1287} 1295}
1288 1296
1297/* Handler for [REGSLEEP -> ENABLED] transition */
1298static int omap_mmc_regsleep_to_enabled(struct mmc_omap_host *host)
1299{
1300 unsigned long timeout;
1301
1302 dev_dbg(mmc_dev(host->mmc), "REGSLEEP -> ENABLED\n");
1303
1304 clk_enable(host->fclk);
1305 clk_enable(host->iclk);
1306
1307 if (clk_enable(host->dbclk))
1308 dev_dbg(mmc_dev(host->mmc),
1309 "Enabling debounce clk failed\n");
1310
1311 omap_mmc_restore_ctx(host);
1312
1313 /*
1314 * We turned off interrupts and bus power. Interrupts
1315 * are turned on by 'mmc_omap_start_command()' so we
1316 * just need to turn on the bus power here.
1317 */
1318 OMAP_HSMMC_WRITE(host->base, HCTL,
1319 OMAP_HSMMC_READ(host->base, HCTL) | SDBP);
1320
1321 timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
1322 while ((OMAP_HSMMC_READ(host->base, HCTL) & SDBP) != SDBP &&
1323 time_before(jiffies, timeout))
1324 ;
1325
1326 if (mmc_slot(host).set_sleep)
1327 mmc_slot(host).set_sleep(host->dev, host->slot_id,
1328 0, host->vdd, 0);
1329
1330 host->dpm_state = ENABLED;
1331
1332 return 0;
1333}
1334
1289/* 1335/*
1290 * Bring MMC host to ENABLED from any other PM state. 1336 * Bring MMC host to ENABLED from any other PM state.
1291 */ 1337 */
@@ -1296,6 +1342,8 @@ static int omap_mmc_enable(struct mmc_host *mmc)
1296 switch (host->dpm_state) { 1342 switch (host->dpm_state) {
1297 case DISABLED: 1343 case DISABLED:
1298 return omap_mmc_disabled_to_enabled(host); 1344 return omap_mmc_disabled_to_enabled(host);
1345 case REGSLEEP:
1346 return omap_mmc_regsleep_to_enabled(host);
1299 case OFF: 1347 case OFF:
1300 return omap_mmc_off_to_enabled(host); 1348 return omap_mmc_off_to_enabled(host);
1301 default: 1349 default:
@@ -1393,7 +1441,8 @@ static int mmc_regs_show(struct seq_file *s, void *data)
1393 host->dpm_state, mmc->nesting_cnt, 1441 host->dpm_state, mmc->nesting_cnt,
1394 host->context_loss, context_loss); 1442 host->context_loss, context_loss);
1395 1443
1396 if (host->suspended || host->dpm_state == OFF) { 1444 if (host->suspended || host->dpm_state == OFF ||
1445 host->dpm_state == REGSLEEP) {
1397 seq_printf(s, "host suspended, can't read registers\n"); 1446 seq_printf(s, "host suspended, can't read registers\n");
1398 return 0; 1447 return 0;
1399 } 1448 }