aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGirish K S <girish.shivananjappa@linaro.org>2012-01-31 05:14:03 -0500
committerChris Ball <cjb@laptop.org>2012-02-13 20:39:02 -0500
commit3e73c36b4dc224529d0b0c0d5d69c0dacd793c42 (patch)
tree9c6df98a296ca4865db3621f0bc295d687272f66
parent012e4671e445ac1dd04f40c0b974685280bedca3 (diff)
mmc: core: Fix PowerOff Notify suspend/resume
Modified the mmc_poweroff to resume before sending the poweroff notification command. In sleep mode only AWAKE and RESET commands are allowed, so before sending the poweroff notification command resume from sleep mode and then send the notification command. PowerOff Notify is tested on a Synopsis Designware Host Controller (eMMC 4.5). The suspend to RAM and resume works fine. Signed-off-by: Girish K S <girish.shivananjappa@linaro.org> Tested-by: Girish K S <girish.shivananjappa@linaro.org> Reviewed-by: Saugata Das <saugata.das@linaro.org> Signed-off-by: Chris Ball <cjb@laptop.org>
-rw-r--r--drivers/mmc/core/core.c26
-rw-r--r--drivers/mmc/core/mmc.c17
-rw-r--r--include/linux/mmc/card.h4
3 files changed, 35 insertions, 12 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 18661554e79c..690255c7d4dc 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1256,6 +1256,7 @@ static void mmc_poweroff_notify(struct mmc_host *host)
1256 int err = 0; 1256 int err = 0;
1257 1257
1258 card = host->card; 1258 card = host->card;
1259 mmc_claim_host(host);
1259 1260
1260 /* 1261 /*
1261 * Send power notify command only if card 1262 * Send power notify command only if card
@@ -1286,6 +1287,7 @@ static void mmc_poweroff_notify(struct mmc_host *host)
1286 /* Set the card state to no notification after the poweroff */ 1287 /* Set the card state to no notification after the poweroff */
1287 card->poweroff_notify_state = MMC_NO_POWER_NOTIFICATION; 1288 card->poweroff_notify_state = MMC_NO_POWER_NOTIFICATION;
1288 } 1289 }
1290 mmc_release_host(host);
1289} 1291}
1290 1292
1291/* 1293/*
@@ -1344,12 +1346,28 @@ static void mmc_power_up(struct mmc_host *host)
1344 1346
1345void mmc_power_off(struct mmc_host *host) 1347void mmc_power_off(struct mmc_host *host)
1346{ 1348{
1349 int err = 0;
1347 mmc_host_clk_hold(host); 1350 mmc_host_clk_hold(host);
1348 1351
1349 host->ios.clock = 0; 1352 host->ios.clock = 0;
1350 host->ios.vdd = 0; 1353 host->ios.vdd = 0;
1351 1354
1352 mmc_poweroff_notify(host); 1355 /*
1356 * For eMMC 4.5 device send AWAKE command before
1357 * POWER_OFF_NOTIFY command, because in sleep state
1358 * eMMC 4.5 devices respond to only RESET and AWAKE cmd
1359 */
1360 if (host->card && mmc_card_is_sleep(host->card) &&
1361 host->bus_ops->resume) {
1362 err = host->bus_ops->resume(host);
1363
1364 if (!err)
1365 mmc_poweroff_notify(host);
1366 else
1367 pr_warning("%s: error %d during resume "
1368 "(continue with poweroff sequence)\n",
1369 mmc_hostname(host), err);
1370 }
1353 1371
1354 /* 1372 /*
1355 * Reset ocr mask to be the highest possible voltage supported for 1373 * Reset ocr mask to be the highest possible voltage supported for
@@ -2403,12 +2421,6 @@ int mmc_suspend_host(struct mmc_host *host)
2403 */ 2421 */
2404 if (mmc_try_claim_host(host)) { 2422 if (mmc_try_claim_host(host)) {
2405 if (host->bus_ops->suspend) { 2423 if (host->bus_ops->suspend) {
2406 /*
2407 * For eMMC 4.5 device send notify command
2408 * before sleep, because in sleep state eMMC 4.5
2409 * devices respond to only RESET and AWAKE cmd
2410 */
2411 mmc_poweroff_notify(host);
2412 err = host->bus_ops->suspend(host); 2424 err = host->bus_ops->suspend(host);
2413 } 2425 }
2414 mmc_do_release_host(host); 2426 mmc_do_release_host(host);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index dd3fcac684a3..9be031934e33 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1316,11 +1316,13 @@ static int mmc_suspend(struct mmc_host *host)
1316 BUG_ON(!host->card); 1316 BUG_ON(!host->card);
1317 1317
1318 mmc_claim_host(host); 1318 mmc_claim_host(host);
1319 if (mmc_card_can_sleep(host)) 1319 if (mmc_card_can_sleep(host)) {
1320 err = mmc_card_sleep(host); 1320 err = mmc_card_sleep(host);
1321 else if (!mmc_host_is_spi(host)) 1321 if (!err)
1322 mmc_card_set_sleep(host->card);
1323 } else if (!mmc_host_is_spi(host))
1322 mmc_deselect_cards(host); 1324 mmc_deselect_cards(host);
1323 host->card->state &= ~MMC_STATE_HIGHSPEED; 1325 host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
1324 mmc_release_host(host); 1326 mmc_release_host(host);
1325 1327
1326 return err; 1328 return err;
@@ -1340,7 +1342,11 @@ static int mmc_resume(struct mmc_host *host)
1340 BUG_ON(!host->card); 1342 BUG_ON(!host->card);
1341 1343
1342 mmc_claim_host(host); 1344 mmc_claim_host(host);
1343 err = mmc_init_card(host, host->ocr, host->card); 1345 if (mmc_card_is_sleep(host->card)) {
1346 err = mmc_card_awake(host);
1347 mmc_card_clr_sleep(host->card);
1348 } else
1349 err = mmc_init_card(host, host->ocr, host->card);
1344 mmc_release_host(host); 1350 mmc_release_host(host);
1345 1351
1346 return err; 1352 return err;
@@ -1350,7 +1356,8 @@ static int mmc_power_restore(struct mmc_host *host)
1350{ 1356{
1351 int ret; 1357 int ret;
1352 1358
1353 host->card->state &= ~MMC_STATE_HIGHSPEED; 1359 host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
1360 mmc_card_clr_sleep(host->card);
1354 mmc_claim_host(host); 1361 mmc_claim_host(host);
1355 ret = mmc_init_card(host, host->ocr, host->card); 1362 ret = mmc_init_card(host, host->ocr, host->card);
1356 mmc_release_host(host); 1363 mmc_release_host(host);
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 9f22ba572de0..19a41d1737af 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -217,6 +217,7 @@ struct mmc_card {
217#define MMC_CARD_SDXC (1<<6) /* card is SDXC */ 217#define MMC_CARD_SDXC (1<<6) /* card is SDXC */
218#define MMC_CARD_REMOVED (1<<7) /* card has been removed */ 218#define MMC_CARD_REMOVED (1<<7) /* card has been removed */
219#define MMC_STATE_HIGHSPEED_200 (1<<8) /* card is in HS200 mode */ 219#define MMC_STATE_HIGHSPEED_200 (1<<8) /* card is in HS200 mode */
220#define MMC_STATE_SLEEP (1<<9) /* card is in sleep state */
220 unsigned int quirks; /* card quirks */ 221 unsigned int quirks; /* card quirks */
221#define MMC_QUIRK_LENIENT_FN0 (1<<0) /* allow SDIO FN0 writes outside of the VS CCCR range */ 222#define MMC_QUIRK_LENIENT_FN0 (1<<0) /* allow SDIO FN0 writes outside of the VS CCCR range */
222#define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func->cur_blksize */ 223#define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func->cur_blksize */
@@ -382,6 +383,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
382#define mmc_sd_card_uhs(c) ((c)->state & MMC_STATE_ULTRAHIGHSPEED) 383#define mmc_sd_card_uhs(c) ((c)->state & MMC_STATE_ULTRAHIGHSPEED)
383#define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC) 384#define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
384#define mmc_card_removed(c) ((c) && ((c)->state & MMC_CARD_REMOVED)) 385#define mmc_card_removed(c) ((c) && ((c)->state & MMC_CARD_REMOVED))
386#define mmc_card_is_sleep(c) ((c)->state & MMC_STATE_SLEEP)
385 387
386#define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT) 388#define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT)
387#define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY) 389#define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
@@ -393,7 +395,9 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
393#define mmc_sd_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED) 395#define mmc_sd_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
394#define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC) 396#define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
395#define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED) 397#define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
398#define mmc_card_set_sleep(c) ((c)->state |= MMC_STATE_SLEEP)
396 399
400#define mmc_card_clr_sleep(c) ((c)->state &= ~MMC_STATE_SLEEP)
397/* 401/*
398 * Quirk add/remove for MMC products. 402 * Quirk add/remove for MMC products.
399 */ 403 */