Skip to content

Commit

Permalink
mmc: core: Fix power_off_notify during suspend
Browse files Browse the repository at this point in the history
The eMMC 4.5 devices respond to only RESET and AWAKE command in the
sleep state. Hence the mmc switch command to notify power off state
should be sent before the device enters sleep state.

This patch fixes the same.

Signed-off-by: Girish K S <girish.shivananjappa@linaro.org>
Signed-off-by: Chris Ball <cjb@laptop.org>
  • Loading branch information
Girish K S authored and Chris Ball committed Dec 10, 2011
1 parent 96a85d5 commit a80f162
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 33 deletions.
81 changes: 49 additions & 32 deletions drivers/mmc/core/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1225,6 +1225,46 @@ void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type)
mmc_host_clk_release(host);
}

static void mmc_poweroff_notify(struct mmc_host *host)
{
struct mmc_card *card;
unsigned int timeout;
unsigned int notify_type = EXT_CSD_NO_POWER_NOTIFICATION;
int err = 0;

card = host->card;

/*
* Send power notify command only if card
* is mmc and notify state is powered ON
*/
if (card && mmc_card_mmc(card) &&
(card->poweroff_notify_state == MMC_POWERED_ON)) {

if (host->power_notify_type == MMC_HOST_PW_NOTIFY_SHORT) {
notify_type = EXT_CSD_POWER_OFF_SHORT;
timeout = card->ext_csd.generic_cmd6_time;
card->poweroff_notify_state = MMC_POWEROFF_SHORT;
} else {
notify_type = EXT_CSD_POWER_OFF_LONG;
timeout = card->ext_csd.power_off_longtime;
card->poweroff_notify_state = MMC_POWEROFF_LONG;
}

err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_POWER_OFF_NOTIFICATION,
notify_type, timeout);

if (err && err != -EBADMSG)
pr_err("Device failed to respond within %d poweroff "
"time. Forcefully powering down the device\n",
timeout);

/* Set the card state to no notification after the poweroff */
card->poweroff_notify_state = MMC_NO_POWER_NOTIFICATION;
}
}

/*
* Apply power to the MMC stack. This is a two-stage process.
* First, we enable power to the card without the clock running.
Expand Down Expand Up @@ -1281,42 +1321,12 @@ static void mmc_power_up(struct mmc_host *host)

void mmc_power_off(struct mmc_host *host)
{
struct mmc_card *card;
unsigned int notify_type;
unsigned int timeout;
int err;

mmc_host_clk_hold(host);

card = host->card;
host->ios.clock = 0;
host->ios.vdd = 0;

if (card && mmc_card_mmc(card) &&
(card->poweroff_notify_state == MMC_POWERED_ON)) {

if (host->power_notify_type == MMC_HOST_PW_NOTIFY_SHORT) {
notify_type = EXT_CSD_POWER_OFF_SHORT;
timeout = card->ext_csd.generic_cmd6_time;
card->poweroff_notify_state = MMC_POWEROFF_SHORT;
} else {
notify_type = EXT_CSD_POWER_OFF_LONG;
timeout = card->ext_csd.power_off_longtime;
card->poweroff_notify_state = MMC_POWEROFF_LONG;
}

err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_POWER_OFF_NOTIFICATION,
notify_type, timeout);

if (err && err != -EBADMSG)
pr_err("Device failed to respond within %d poweroff "
"time. Forcefully powering down the device\n",
timeout);

/* Set the card state to no notification after the poweroff */
card->poweroff_notify_state = MMC_NO_POWER_NOTIFICATION;
}
mmc_poweroff_notify(host);

/*
* Reset ocr mask to be the highest possible voltage supported for
Expand Down Expand Up @@ -2314,8 +2324,15 @@ int mmc_suspend_host(struct mmc_host *host)
* pre-claim the host.
*/
if (mmc_try_claim_host(host)) {
if (host->bus_ops->suspend)
if (host->bus_ops->suspend) {
/*
* For eMMC 4.5 device send notify command
* before sleep, because in sleep state eMMC 4.5
* devices respond to only RESET and AWAKE cmd
*/
mmc_poweroff_notify(host);
err = host->bus_ops->suspend(host);
}
if (err == -ENOSYS || !host->bus_ops->resume) {
/*
* We simply "remove" the card in this case.
Expand Down
2 changes: 1 addition & 1 deletion drivers/mmc/core/mmc.c
Original file line number Diff line number Diff line change
Expand Up @@ -876,7 +876,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
* set the notification byte in the ext_csd register of device
*/
if ((host->caps2 & MMC_CAP2_POWEROFF_NOTIFY) &&
(card->poweroff_notify_state == MMC_NO_POWER_NOTIFICATION)) {
(card->ext_csd.rev >= 6)) {
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_POWER_OFF_NOTIFICATION,
EXT_CSD_POWER_ON,
Expand Down

0 comments on commit a80f162

Please sign in to comment.