summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/mmc/core/mmc.c36
-rw-r--r--include/linux/mmc/card.h5
2 files changed, 40 insertions, 1 deletions
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 440d7a0a99be..461a150109fb 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -19,6 +19,7 @@
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
#include <linux/mmc/mmc.h>
+#include <linux/reboot.h>
#include "core.h"
#include "host.h"
@@ -1364,6 +1365,20 @@ out:
return err;
}
+static int mmc_reboot_notify(struct notifier_block *notify_block,
+ unsigned long event, void *unused)
+{
+ struct mmc_card *card = container_of(
+ notify_block, struct mmc_card, reboot_notify);
+
+ if (event != SYS_RESTART)
+ card->issue_long_pon = true;
+ else
+ card->issue_long_pon = false;
+
+ return NOTIFY_OK;
+}
+
/*
* Activate High Speed or HS200 mode if supported.
*/
@@ -1495,6 +1510,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
card->rca = 1;
memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
host->card = card;
+ card->reboot_notify.notifier_call = mmc_reboot_notify;
}
/*
@@ -1838,6 +1854,22 @@ static int mmc_poweroff_notify(struct mmc_card *card, unsigned int notify_type)
return err;
}
+int mmc_send_long_pon(struct mmc_card *card)
+{
+ int err = 0;
+ struct mmc_host *host = card->host;
+
+ mmc_claim_host(host);
+ if (card->issue_long_pon && mmc_can_poweroff_notify(card)) {
+ err = mmc_poweroff_notify(host->card, EXT_CSD_POWER_OFF_LONG);
+ if (err)
+ pr_warning("%s: error %d sending Long PON",
+ mmc_hostname(host), err);
+ }
+ mmc_release_host(host);
+ return err;
+}
+
/*
* Host is being removed. Free up the current card.
*/
@@ -1846,6 +1878,7 @@ static void mmc_remove(struct mmc_host *host)
BUG_ON(!host);
BUG_ON(!host->card);
+ unregister_reboot_notifier(&host->card->reboot_notify);
mmc_remove_card(host->card);
mmc_claim_host(host);
@@ -2166,6 +2199,9 @@ int mmc_attach_mmc(struct mmc_host *host)
goto remove_card;
mmc_claim_host(host);
+
+ register_reboot_notifier(&host->card->reboot_notify);
+
return 0;
remove_card:
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 968bf8b113e6..c18556450f08 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -13,6 +13,7 @@
#include <linux/device.h>
#include <linux/mmc/core.h>
#include <linux/mod_devicetable.h>
+#include <linux/notifier.h>
struct mmc_cid {
unsigned int manfid;
@@ -342,6 +343,8 @@ struct mmc_card {
unsigned int part_curr;
struct mmc_wr_pack_stats wr_pack_stats; /* packed commands stats*/
+ struct notifier_block reboot_notify;
+ bool issue_long_pon;
};
/*
@@ -563,5 +566,5 @@ extern void mmc_fixup_device(struct mmc_card *card,
extern struct mmc_wr_pack_stats *mmc_blk_get_packed_statistics(
struct mmc_card *card);
extern void mmc_blk_init_packed_statistics(struct mmc_card *card);
-
+extern int mmc_send_long_pon(struct mmc_card *card);
#endif /* LINUX_MMC_CARD_H */