Commit 3e73c36b4dc224529d0b0c0d5d69c0dacd793c42
Committed by
Chris Ball
1 parent
012e4671e4
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
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>
Showing 3 changed files with 35 additions and 12 deletions Side-by-side Diff
drivers/mmc/core/core.c
... | ... | @@ -1256,6 +1256,7 @@ |
1256 | 1256 | int err = 0; |
1257 | 1257 | |
1258 | 1258 | card = host->card; |
1259 | + mmc_claim_host(host); | |
1259 | 1260 | |
1260 | 1261 | /* |
1261 | 1262 | * Send power notify command only if card |
... | ... | @@ -1286,6 +1287,7 @@ |
1286 | 1287 | /* Set the card state to no notification after the poweroff */ |
1287 | 1288 | card->poweroff_notify_state = MMC_NO_POWER_NOTIFICATION; |
1288 | 1289 | } |
1290 | + mmc_release_host(host); | |
1289 | 1291 | } |
1290 | 1292 | |
1291 | 1293 | /* |
1292 | 1294 | |
1293 | 1295 | |
... | ... | @@ -1344,13 +1346,29 @@ |
1344 | 1346 | |
1345 | 1347 | void mmc_power_off(struct mmc_host *host) |
1346 | 1348 | { |
1349 | + int err = 0; | |
1347 | 1350 | mmc_host_clk_hold(host); |
1348 | 1351 | |
1349 | 1352 | host->ios.clock = 0; |
1350 | 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); | |
1353 | 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 | + } | |
1371 | + | |
1354 | 1372 | /* |
1355 | 1373 | * Reset ocr mask to be the highest possible voltage supported for |
1356 | 1374 | * this mmc host. This value will be used at next power up. |
... | ... | @@ -2403,12 +2421,6 @@ |
2403 | 2421 | */ |
2404 | 2422 | if (mmc_try_claim_host(host)) { |
2405 | 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 | 2424 | err = host->bus_ops->suspend(host); |
2413 | 2425 | } |
2414 | 2426 | mmc_do_release_host(host); |
drivers/mmc/core/mmc.c
... | ... | @@ -1316,11 +1316,13 @@ |
1316 | 1316 | BUG_ON(!host->card); |
1317 | 1317 | |
1318 | 1318 | mmc_claim_host(host); |
1319 | - if (mmc_card_can_sleep(host)) | |
1319 | + if (mmc_card_can_sleep(host)) { | |
1320 | 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 | 1324 | mmc_deselect_cards(host); |
1323 | - host->card->state &= ~MMC_STATE_HIGHSPEED; | |
1325 | + host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200); | |
1324 | 1326 | mmc_release_host(host); |
1325 | 1327 | |
1326 | 1328 | return err; |
... | ... | @@ -1340,7 +1342,11 @@ |
1340 | 1342 | BUG_ON(!host->card); |
1341 | 1343 | |
1342 | 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 | 1350 | mmc_release_host(host); |
1345 | 1351 | |
1346 | 1352 | return err; |
... | ... | @@ -1350,7 +1356,8 @@ |
1350 | 1356 | { |
1351 | 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 | 1361 | mmc_claim_host(host); |
1355 | 1362 | ret = mmc_init_card(host, host->ocr, host->card); |
1356 | 1363 | mmc_release_host(host); |
include/linux/mmc/card.h
... | ... | @@ -217,6 +217,7 @@ |
217 | 217 | #define MMC_CARD_SDXC (1<<6) /* card is SDXC */ |
218 | 218 | #define MMC_CARD_REMOVED (1<<7) /* card has been removed */ |
219 | 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 | 221 | unsigned int quirks; /* card quirks */ |
221 | 222 | #define MMC_QUIRK_LENIENT_FN0 (1<<0) /* allow SDIO FN0 writes outside of the VS CCCR range */ |
222 | 223 | #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func->cur_blksize */ |
... | ... | @@ -382,6 +383,7 @@ |
382 | 383 | #define mmc_sd_card_uhs(c) ((c)->state & MMC_STATE_ULTRAHIGHSPEED) |
383 | 384 | #define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC) |
384 | 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 | 388 | #define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT) |
387 | 389 | #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY) |
388 | 390 | |
... | ... | @@ -393,7 +395,9 @@ |
393 | 395 | #define mmc_sd_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED) |
394 | 396 | #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC) |
395 | 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 | 402 | * Quirk add/remove for MMC products. |
399 | 403 | */ |