diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 926e0fd..4bbe3eb 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1197,6 +1197,19 @@ void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
 	mmc_set_ios(host);
 }
 
+void mmc_set_init_state(struct mmc_host *host)
+{
+	host->ios.bus_mode = host->cached_ios.bus_mode;
+	host->ios.bus_width = host->cached_ios.bus_width;
+	host->ios.timing = host->cached_ios.timing;
+	if (host->card &&
+	    host->card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES &&
+	    host->cached_ios.timing == MMC_TIMING_MMC_HS400)
+		host->ios.enhanced_strobe = true;
+
+	mmc_set_ios(host);
+}
+
 /*
  * Set initial state after a power cycle or a hw_reset.
  */
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index 55f543f..9476a89 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -58,6 +58,7 @@ int mmc_select_drive_strength(struct mmc_card *card, unsigned int max_dtr,
 void mmc_power_off(struct mmc_host *host);
 void mmc_power_cycle(struct mmc_host *host, u32 ocr);
 void mmc_set_initial_state(struct mmc_host *host);
+void mmc_set_init_state(struct mmc_host *host);
 
 static inline void mmc_delay(unsigned int ms)
 {
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 83bcc86..f7c244c 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1827,6 +1827,28 @@ static int mmc_can_sleep(struct mmc_card *card)
 	return (card && card->ext_csd.rev >= 3);
 }
 
+static int mmc_can_sleepawake_mode(struct mmc_host *host)
+{
+	/*
+	 * Disabled for HS400 mode since it requires tuning
+	 * to be done in HS200 timing and then switching
+	 * to HS400 mode.
+	 */
+	switch (host->cached_ios.timing) {
+	case MMC_TIMING_MMC_HS400:
+		if (!(host->card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES))
+			return 0;
+	default:
+		return 1;
+	}
+}
+
+static int mmc_can_sleepawake(struct mmc_host *host)
+{
+	return (host && host->caps2 & MMC_CAP2_SLEEP_AWAKE &&
+		mmc_can_sleep(host->card) && mmc_can_sleepawake_mode(host));
+}
+
 static int mmc_sleepawake(struct mmc_host *host, bool sleep)
 {
 	struct mmc_command cmd = {};
@@ -1964,6 +1986,100 @@ static void mmc_detect(struct mmc_host *host)
 	}
 }
 
+static int mmc_cache_card_ext_csd(struct mmc_host *host)
+{
+	int err;
+	u8 *ext_csd;
+	struct mmc_card *card = host->card;
+
+	err = mmc_get_ext_csd(card, &ext_csd);
+	if (err || !ext_csd) {
+		pr_err("%s: %s: mmc_get_ext_csd failed (%d)\n",
+		       mmc_hostname(host), __func__, err);
+		return err;
+	}
+
+	/* only cache read/write fields that the sw changes */
+	card->ext_csd.raw_ext_csd_cache_ctrl = ext_csd[EXT_CSD_CACHE_CTRL];
+	card->ext_csd.raw_ext_csd_bus_width = ext_csd[EXT_CSD_BUS_WIDTH];
+	card->ext_csd.raw_ext_csd_hs_timing = ext_csd[EXT_CSD_HS_TIMING];
+	kfree(ext_csd);
+	return 0;
+}
+
+static int mmc_test_awake_ext_csd(struct mmc_host *host)
+{
+	int err;
+	u8 *ext_csd;
+	struct mmc_card *card = host->card;
+
+	return 0;
+	err = mmc_get_ext_csd(card, &ext_csd);
+	if (err) {
+		pr_err("%s: %s: mmc_get_ext_csd failed (%d)\n",
+		       mmc_hostname(host), __func__, err);
+		return err;
+	}
+
+	/* only compare read/write fields that the sw changes */
+	pr_debug("%s: %s: type(cached:current) cache_ctrl(%d:%d) bus_width (%d:%d) timing(%d:%d)\n",
+		 mmc_hostname(host), __func__,
+		 card->ext_csd.raw_ext_csd_cache_ctrl,
+		 ext_csd[EXT_CSD_CACHE_CTRL],
+		 card->ext_csd.raw_ext_csd_bus_width,
+		 ext_csd[EXT_CSD_BUS_WIDTH],
+		 card->ext_csd.raw_ext_csd_hs_timing,
+		 ext_csd[EXT_CSD_HS_TIMING]);
+
+	err = !((card->ext_csd.raw_ext_csd_cache_ctrl ==
+			ext_csd[EXT_CSD_CACHE_CTRL]) &&
+		(card->ext_csd.raw_ext_csd_bus_width ==
+			ext_csd[EXT_CSD_BUS_WIDTH]) &&
+		(card->ext_csd.raw_ext_csd_hs_timing ==
+			ext_csd[EXT_CSD_HS_TIMING]));
+
+	kfree(ext_csd);
+	return err;
+}
+
+static int mmc_partial_init(struct mmc_host *host)
+{
+	int err = 0;
+	struct mmc_card *card = host->card;
+
+	mmc_set_init_state(host);
+	mmc_set_clock(host, host->cached_ios.clock);
+	if (mmc_card_hs400(card)) {
+		if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES) {
+			if (host->ops->hs400_enhanced_strobe)
+				host->ops->hs400_enhanced_strobe(host,
+								 &host->ios);
+		}
+	} else if (mmc_card_hs200(card)) {
+		err = mmc_hs200_tuning(card);
+		if (err)
+			pr_warn("%s: %s: tuning execution failed (%d)\n",
+				mmc_hostname(host), __func__, err);
+	}
+
+	/*
+	 * The ext_csd is read to make sure the card did not went through
+	 * Power-failure during sleep period.
+	 * A subset of the W/E_P, W/C_P register will be tested. In case
+	 * these registers values are different from the values that were
+	 * cached during suspend, we will conclude that a Power-failure occurred
+	 * and will do full initialization sequence.
+	 */
+	err = mmc_test_awake_ext_csd(host);
+	if (err) {
+		pr_err("%s: %s: fail on ext_csd read (%d)\n",
+		       mmc_hostname(host), __func__, err);
+		goto out;
+	}
+out:
+	return err;
+}
+
 static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
 {
 	int err = 0;
@@ -1988,7 +2104,11 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
 	if (mmc_can_poweroff_notify(host->card) &&
 		((host->caps2 & MMC_CAP2_FULL_PWR_CYCLE) || !is_suspend))
 		err = mmc_poweroff_notify(host->card, notify_type);
-	else if (mmc_can_sleep(host->card))
+	else if (mmc_can_sleepawake(host)) {
+		memcpy(&host->cached_ios, &host->ios, sizeof(host->cached_ios));
+		mmc_cache_card_ext_csd(host);
+		err = mmc_sleep(host);
+	} else if (mmc_can_sleep(host->card))
 		err = mmc_sleep(host);
 	else if (!mmc_host_is_spi(host))
 		err = mmc_deselect_cards(host);
@@ -2032,7 +2152,17 @@ static int _mmc_resume(struct mmc_host *host)
 		goto out;
 
 	mmc_power_up(host, host->card->ocr);
-	err = mmc_init_card(host, host->card->ocr, host->card);
+	if (mmc_can_sleepawake(host)) {
+		err = mmc_awake(host);
+		if (!err)
+			err = mmc_partial_init(host);
+		if (err)
+			pr_err("%s: awake failed (%d), fallback to full init\n",
+			       mmc_hostname(host), err);
+	}
+	if (err || !mmc_can_sleepawake(host))
+		err = mmc_init_card(host, host->card->ocr, host->card);
+
 	mmc_card_clr_suspended(host->card);
 
 out:
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 77e61e0..9aa2c97 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -93,11 +93,14 @@ struct mmc_ext_csd {
 	unsigned int		cmdq_depth;	/* Command Queue depth */
 #define MMC_FIRMWARE_LEN 8
 	u8			fwrev[MMC_FIRMWARE_LEN];  /* FW version */
+	u8			raw_ext_csd_cache_ctrl;	/* 33 */
 	u8			raw_exception_status;	/* 54 */
 	u8			raw_partition_support;	/* 160 */
 	u8			raw_rpmb_size_mult;	/* 168 */
 	u8			raw_erased_mem_count;	/* 181 */
+	u8			raw_ext_csd_bus_width;	/* 183 */
 	u8			strobe_support;		/* 184 */
+	u8			raw_ext_csd_hs_timing;	/* 185 */
 	u8			raw_ext_csd_structure;	/* 194 */
 	u8			raw_card_type;		/* 196 */
 	u8			raw_driver_strength;	/* 197 */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index df7882b..c89407c 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -320,6 +320,7 @@ struct mmc_host {
 	spinlock_t		lock;		/* lock for claim and bus ops */
 
 	struct mmc_ios		ios;		/* current io bus settings */
+	struct mmc_ios		cached_ios;
 
 	/* group bitfields together to minimize padding */
 	unsigned int		use_spi_crc:1;
