aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorUlf Hansson <ulf.hansson@linaro.org>2012-10-05 12:45:39 -0400
committerChris Ball <cjb@laptop.org>2012-10-07 17:41:45 -0400
commite6c085863f97f0a8f009753e1baaf83e4aac7b42 (patch)
tree10819da5eb65d1919023ea540bb1580ebdb50dae /drivers/mmc
parentda764f97df0e5e05e5453279f934531c0cf52e11 (diff)
mmc: core: Fixup broken suspend and eMMC4.5 power off notify
This patch fixes up the broken suspend sequence for eMMC with sleep support. Additionally it reworks the eMMC4.5 Power Off Notification feature so it fits together with the existing sleep feature. The CMD0 based re-initialization of the eMMC at resume is re-introduced to maintain compatiblity for devices using sleep. A host shall use MMC_CAP2_POWEROFF_NOTIFY to enable the Power Off Notification feature. We might be able to remove this cap later on, if we think that Power Off Notification always is preferred over sleep, even if the host is not able to cut the eMMC VCCQ power. Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Signed-off-by: Saugata Das <saugata.das@linaro.org> Acked-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/core/core.c62
-rw-r--r--drivers/mmc/core/mmc.c46
-rw-r--r--drivers/mmc/host/dw_mmc.c5
-rw-r--r--drivers/mmc/host/sdhci.c9
4 files changed, 35 insertions, 87 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 66121633c9cd..06c42cfb7c34 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1273,48 +1273,6 @@ void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type)
1273 mmc_host_clk_release(host); 1273 mmc_host_clk_release(host);
1274} 1274}
1275 1275
1276static void mmc_poweroff_notify(struct mmc_host *host)
1277{
1278 struct mmc_card *card;
1279 unsigned int timeout;
1280 unsigned int notify_type = EXT_CSD_NO_POWER_NOTIFICATION;
1281 int err = 0;
1282
1283 card = host->card;
1284 mmc_claim_host(host);
1285
1286 /*
1287 * Send power notify command only if card
1288 * is mmc and notify state is powered ON
1289 */
1290 if (card && mmc_card_mmc(card) &&
1291 (card->poweroff_notify_state == MMC_POWERED_ON)) {
1292
1293 if (host->power_notify_type == MMC_HOST_PW_NOTIFY_SHORT) {
1294 notify_type = EXT_CSD_POWER_OFF_SHORT;
1295 timeout = card->ext_csd.generic_cmd6_time;
1296 card->poweroff_notify_state = MMC_POWEROFF_SHORT;
1297 } else {
1298 notify_type = EXT_CSD_POWER_OFF_LONG;
1299 timeout = card->ext_csd.power_off_longtime;
1300 card->poweroff_notify_state = MMC_POWEROFF_LONG;
1301 }
1302
1303 err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
1304 EXT_CSD_POWER_OFF_NOTIFICATION,
1305 notify_type, timeout);
1306
1307 if (err && err != -EBADMSG)
1308 pr_err("Device failed to respond within %d poweroff "
1309 "time. Forcefully powering down the device\n",
1310 timeout);
1311
1312 /* Set the card state to no notification after the poweroff */
1313 card->poweroff_notify_state = MMC_NO_POWER_NOTIFICATION;
1314 }
1315 mmc_release_host(host);
1316}
1317
1318/* 1276/*
1319 * Apply power to the MMC stack. This is a two-stage process. 1277 * Apply power to the MMC stack. This is a two-stage process.
1320 * First, we enable power to the card without the clock running. 1278 * First, we enable power to the card without the clock running.
@@ -1377,8 +1335,6 @@ static void mmc_power_up(struct mmc_host *host)
1377 1335
1378void mmc_power_off(struct mmc_host *host) 1336void mmc_power_off(struct mmc_host *host)
1379{ 1337{
1380 int err = 0;
1381
1382 if (host->ios.power_mode == MMC_POWER_OFF) 1338 if (host->ios.power_mode == MMC_POWER_OFF)
1383 return; 1339 return;
1384 1340
@@ -1387,22 +1343,6 @@ void mmc_power_off(struct mmc_host *host)
1387 host->ios.clock = 0; 1343 host->ios.clock = 0;
1388 host->ios.vdd = 0; 1344 host->ios.vdd = 0;
1389 1345
1390 /*
1391 * For eMMC 4.5 device send AWAKE command before
1392 * POWER_OFF_NOTIFY command, because in sleep state
1393 * eMMC 4.5 devices respond to only RESET and AWAKE cmd
1394 */
1395 if (host->card && mmc_card_is_sleep(host->card) &&
1396 host->bus_ops->resume) {
1397 err = host->bus_ops->resume(host);
1398
1399 if (!err)
1400 mmc_poweroff_notify(host);
1401 else
1402 pr_warning("%s: error %d during resume "
1403 "(continue with poweroff sequence)\n",
1404 mmc_hostname(host), err);
1405 }
1406 1346
1407 /* 1347 /*
1408 * Reset ocr mask to be the highest possible voltage supported for 1348 * Reset ocr mask to be the highest possible voltage supported for
@@ -2579,7 +2519,6 @@ int mmc_pm_notify(struct notifier_block *notify_block,
2579 2519
2580 spin_lock_irqsave(&host->lock, flags); 2520 spin_lock_irqsave(&host->lock, flags);
2581 host->rescan_disable = 1; 2521 host->rescan_disable = 1;
2582 host->power_notify_type = MMC_HOST_PW_NOTIFY_SHORT;
2583 spin_unlock_irqrestore(&host->lock, flags); 2522 spin_unlock_irqrestore(&host->lock, flags);
2584 cancel_delayed_work_sync(&host->detect); 2523 cancel_delayed_work_sync(&host->detect);
2585 2524
@@ -2603,7 +2542,6 @@ int mmc_pm_notify(struct notifier_block *notify_block,
2603 2542
2604 spin_lock_irqsave(&host->lock, flags); 2543 spin_lock_irqsave(&host->lock, flags);
2605 host->rescan_disable = 0; 2544 host->rescan_disable = 0;
2606 host->power_notify_type = MMC_HOST_PW_NOTIFY_LONG;
2607 spin_unlock_irqrestore(&host->lock, flags); 2545 spin_unlock_irqrestore(&host->lock, flags);
2608 mmc_detect_change(host, 0); 2546 mmc_detect_change(host, 0);
2609 2547
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 7509de14aa78..7cc46382fd64 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1007,7 +1007,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
1007 * so check for success and update the flag 1007 * so check for success and update the flag
1008 */ 1008 */
1009 if (!err) 1009 if (!err)
1010 card->poweroff_notify_state = MMC_POWERED_ON; 1010 card->ext_csd.power_off_notification = EXT_CSD_POWER_ON;
1011 } 1011 }
1012 1012
1013 /* 1013 /*
@@ -1273,6 +1273,35 @@ err:
1273 return err; 1273 return err;
1274} 1274}
1275 1275
1276static int mmc_can_poweroff_notify(const struct mmc_card *card)
1277{
1278 return card &&
1279 mmc_card_mmc(card) &&
1280 (card->ext_csd.power_off_notification == EXT_CSD_POWER_ON);
1281}
1282
1283static int mmc_poweroff_notify(struct mmc_card *card, unsigned int notify_type)
1284{
1285 unsigned int timeout = card->ext_csd.generic_cmd6_time;
1286 int err;
1287
1288 /* Use EXT_CSD_POWER_OFF_SHORT as default notification type. */
1289 if (notify_type == EXT_CSD_POWER_OFF_LONG)
1290 timeout = card->ext_csd.power_off_longtime;
1291
1292 err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
1293 EXT_CSD_POWER_OFF_NOTIFICATION,
1294 notify_type, timeout);
1295 if (err)
1296 pr_err("%s: Power Off Notification timed out, %u\n",
1297 mmc_hostname(card->host), timeout);
1298
1299 /* Disable the power off notification after the switch operation. */
1300 card->ext_csd.power_off_notification = EXT_CSD_NO_POWER_NOTIFICATION;
1301
1302 return err;
1303}
1304
1276/* 1305/*
1277 * Host is being removed. Free up the current card. 1306 * Host is being removed. Free up the current card.
1278 */ 1307 */
@@ -1333,11 +1362,11 @@ static int mmc_suspend(struct mmc_host *host)
1333 BUG_ON(!host->card); 1362 BUG_ON(!host->card);
1334 1363
1335 mmc_claim_host(host); 1364 mmc_claim_host(host);
1336 if (mmc_card_can_sleep(host)) { 1365 if (mmc_can_poweroff_notify(host->card))
1366 err = mmc_poweroff_notify(host->card, EXT_CSD_POWER_OFF_SHORT);
1367 else if (mmc_card_can_sleep(host))
1337 err = mmc_card_sleep(host); 1368 err = mmc_card_sleep(host);
1338 if (!err) 1369 else if (!mmc_host_is_spi(host))
1339 mmc_card_set_sleep(host->card);
1340 } else if (!mmc_host_is_spi(host))
1341 err = mmc_deselect_cards(host); 1370 err = mmc_deselect_cards(host);
1342 host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200); 1371 host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
1343 mmc_release_host(host); 1372 mmc_release_host(host);
@@ -1359,11 +1388,7 @@ static int mmc_resume(struct mmc_host *host)
1359 BUG_ON(!host->card); 1388 BUG_ON(!host->card);
1360 1389
1361 mmc_claim_host(host); 1390 mmc_claim_host(host);
1362 if (mmc_card_is_sleep(host->card)) { 1391 err = mmc_init_card(host, host->ocr, host->card);
1363 err = mmc_card_awake(host);
1364 mmc_card_clr_sleep(host->card);
1365 } else
1366 err = mmc_init_card(host, host->ocr, host->card);
1367 mmc_release_host(host); 1392 mmc_release_host(host);
1368 1393
1369 return err; 1394 return err;
@@ -1374,7 +1399,6 @@ static int mmc_power_restore(struct mmc_host *host)
1374 int ret; 1399 int ret;
1375 1400
1376 host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200); 1401 host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
1377 mmc_card_clr_sleep(host->card);
1378 mmc_claim_host(host); 1402 mmc_claim_host(host);
1379 ret = mmc_init_card(host, host->ocr, host->card); 1403 ret = mmc_init_card(host, host->ocr, host->card);
1380 mmc_release_host(host); 1404 mmc_release_host(host);
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index a23af77de4ce..c2828f35c3b8 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1885,11 +1885,6 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
1885 if (host->pdata->quirks & DW_MCI_QUIRK_HIGHSPEED) 1885 if (host->pdata->quirks & DW_MCI_QUIRK_HIGHSPEED)
1886 mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED; 1886 mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
1887 1887
1888 if (mmc->caps2 & MMC_CAP2_POWEROFF_NOTIFY)
1889 mmc->power_notify_type = MMC_HOST_PW_NOTIFY_SHORT;
1890 else
1891 mmc->power_notify_type = MMC_HOST_PW_NOTIFY_NONE;
1892
1893 if (host->pdata->blk_settings) { 1888 if (host->pdata->blk_settings) {
1894 mmc->max_segs = host->pdata->blk_settings->max_segs; 1889 mmc->max_segs = host->pdata->blk_settings->max_segs;
1895 mmc->max_blk_size = host->pdata->blk_settings->max_blk_size; 1890 mmc->max_blk_size = host->pdata->blk_settings->max_blk_size;
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 0e15c79014fb..7922adb42386 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2886,15 +2886,6 @@ int sdhci_add_host(struct sdhci_host *host)
2886 if (caps[1] & SDHCI_DRIVER_TYPE_D) 2886 if (caps[1] & SDHCI_DRIVER_TYPE_D)
2887 mmc->caps |= MMC_CAP_DRIVER_TYPE_D; 2887 mmc->caps |= MMC_CAP_DRIVER_TYPE_D;
2888 2888
2889 /*
2890 * If Power Off Notify capability is enabled by the host,
2891 * set notify to short power off notify timeout value.
2892 */
2893 if (mmc->caps2 & MMC_CAP2_POWEROFF_NOTIFY)
2894 mmc->power_notify_type = MMC_HOST_PW_NOTIFY_SHORT;
2895 else
2896 mmc->power_notify_type = MMC_HOST_PW_NOTIFY_NONE;
2897
2898 /* Initial value for re-tuning timer count */ 2889 /* Initial value for re-tuning timer count */
2899 host->tuning_count = (caps[1] & SDHCI_RETUNING_TIMER_COUNT_MASK) >> 2890 host->tuning_count = (caps[1] & SDHCI_RETUNING_TIMER_COUNT_MASK) >>
2900 SDHCI_RETUNING_TIMER_COUNT_SHIFT; 2891 SDHCI_RETUNING_TIMER_COUNT_SHIFT;