diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index b4d7f27..5d6b065 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -42,7 +42,8 @@
 #define SDHCI_USE_LEDS_CLASS
 #endif
 
-#define MAX_TUNING_LOOP 40
+#define MAX_TUNING_LOOP 	40
+#define MAX_BUSY_WAIT_LOOP 	100
 
 static unsigned int debug_quirks = 0;
 static unsigned int debug_quirks2;
@@ -2100,6 +2101,44 @@ static const struct mmc_host_ops sdhci_ops = {
 
 /*****************************************************************************\
  *                                                                           *
+ * Workqueues								     *
+ *                                                                           *
+\*****************************************************************************/
+
+/* Internal work. Work to wait for the busy signalling to finish. Certain
+ * eMMC operations may take too long time to complete.
+ */
+static void sdhci_work_wait_for_busy(struct work_struct *work)
+{
+	struct sdhci_host *host = container_of(work, struct sdhci_host,
+					      wait_for_busy_work);
+	int wait_cnt = 0;
+
+	/*
+	 * According to Arasan, when DTOERR occured while CMD38/CMD6,
+	 * which is not treated as normal and as an error by the Host,
+	 * host driver should reset CMD & DATA Lines for SDHC internal state.
+	 */
+	pr_debug("Resetting CMD & DATA Lines at once\n");
+	sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
+
+	pr_info("Waiting for BUSY signalling to end\n");
+	while (wait_cnt++ < MAX_BUSY_WAIT_LOOP &&
+		(sdhci_readl(host, SDHCI_PRESENT_STATE) &
+			SDHCI_DATA_LVL_DAT0_MASK) == 0) {
+		msleep(100);
+        }
+	pr_info("End of BUSY signalling\n");
+
+	if (wait_cnt >= MAX_BUSY_WAIT_LOOP)
+		pr_err("%s: Operation takes too long to finish!\n",
+				mmc_hostname(host->mmc));
+
+	sdhci_finish_command(host);
+}
+
+/*****************************************************************************\
+ *                                                                           *
  * Tasklets                                                                  *
  *                                                                           *
 \*****************************************************************************/
@@ -2328,6 +2367,26 @@ static void sdhci_data_irq(struct sdhci_host *host,
u32 intmask)
 				sdhci_finish_command(host);
 				return;
 			}
+
+			/*
+			 * Some eMMC takes a long time for the erase & certain
+			 * operations to finish. Timeout might be triggered well
+			 * before erase or SWITCH operation finishes. If this
+			 * happens schedule a workqueue work item to monitor
+			 * the DAT0 line to wait for operation to finish.
+			 */
+			if (intmask & SDHCI_INT_DATA_TIMEOUT &&
+					(host->cmd->opcode == MMC_ERASE ||
+					 host->cmd->opcode == MMC_SWITCH)) {
+				if ((sdhci_readl(host, SDHCI_PRESENT_STATE) &
+						SDHCI_DATA_LVL_DAT0_MASK) == 0) {
+					schedule_work(&host->wait_for_busy_work);
+					return;
+				} else {
+					sdhci_finish_command(host);
+					return;
+				}
+			}
 		}
 
 		pr_err("%s: Got data interrupt 0x%08x even "
@@ -2559,6 +2618,9 @@ int sdhci_suspend_host(struct sdhci_host *host)
 		host->flags &= ~SDHCI_NEEDS_RETUNING;
 	}
 
+	/* Flush and wait for busy operation to complete */
+	flush_work(&host->wait_for_busy_work);
+
 	ret = mmc_suspend_host(host->mmc);
 	if (ret) {
 		if (host->flags & SDHCI_USING_RETUNING_TIMER) {
@@ -3206,6 +3268,7 @@ int sdhci_add_host(struct sdhci_host *host)
 		sdhci_tasklet_finish, (unsigned long)host);
 
 	setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host);
+	INIT_WORK(&host->wait_for_busy_work, sdhci_work_wait_for_busy);
 
 	if (host->version >= SDHCI_SPEC_300) {
 		init_waitqueue_head(&host->buf_ready_int);
@@ -3308,6 +3371,9 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
 	sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
 	free_irq(host->irq, host);
 
+	/* Flush and wait for busy operation to complete */
+	flush_work(&host->wait_for_busy_work);
+
 	del_timer_sync(&host->timer);
 
 	tasklet_kill(&host->card_tasklet);
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index 3e781b8..3c86e43 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -144,6 +144,8 @@ struct sdhci_host {
 	bool runtime_suspended;	/* Host is runtime suspended */
 	bool bus_on;		/* Bus power prevents runtime suspend */
 
+	struct work_struct wait_for_busy_work; /* work to wait for busy to end */
+
 	struct mmc_request *mrq;	/* Current request */
 	struct mmc_command *cmd;	/* Current command */
 	struct mmc_data *data;	/* Current data request */
