msm: msm_sdcc: use AUTO_PROG_DONE bit for CMD53 write

SDCCv4 supports AUTO_PROG_DONE bit for CMD53 write.
Without this bit, driver had to send the dummy CMD52
to know whether card is busy programming or not.

As AUTO_PROG_DONE bit is available, driver no longer
sends dummy CMD52 rather it sets this AUTO_PROG_DONE
bit in MCI_DATA_CTL register and then waits for
PROG_DONE interrupt status bit to be set.

Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index d6a343a..9d21c71 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -297,6 +297,8 @@
 {
 	host->curr.data = NULL;
 	host->curr.got_dataend = 0;
+	host->curr.wait_for_auto_prog_done = 0;
+	host->curr.got_auto_prog_done = 0;
 	writel_relaxed(readl_relaxed(host->base + MMCIDATACTRL) &
 			(~(MCI_DPSM_ENABLE)), host->base + MMCIDATACTRL);
 	msmsdcc_delay(host);	/* Allow the DPSM to be reset */
@@ -414,8 +416,9 @@
 	host->dma.sg = NULL;
 	host->dma.busy = 0;
 
-	if (host->curr.got_dataend || mrq->data->error) {
-
+	if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
+		(host->curr.wait_for_auto_prog_done &&
+		host->curr.got_auto_prog_done))) || mrq->data->error) {
 		/*
 		 * If we've already gotten our DATAEND / DATABLKEND
 		 * for this request, then complete it through here.
@@ -566,7 +569,9 @@
 	host->sps.sg = NULL;
 	host->sps.busy = 0;
 
-	if (host->curr.got_dataend || mrq->data->error) {
+	if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
+		(host->curr.wait_for_auto_prog_done &&
+		host->curr.got_auto_prog_done))) || mrq->data->error) {
 		/*
 		 * If we've already gotten our DATAEND / DATABLKEND
 		 * for this request, then complete it through here.
@@ -928,11 +933,15 @@
 	host->curr.xfer_remain = host->curr.xfer_size;
 	host->curr.data_xfered = 0;
 	host->curr.got_dataend = 0;
+	host->curr.got_auto_prog_done = 0;
 
 	memset(&host->pio, 0, sizeof(host->pio));
 
 	datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
 
+	if (host->curr.wait_for_auto_prog_done)
+		datactrl |= MCI_AUTO_PROG_DONE;
+
 	if (!msmsdcc_check_dma_op_req(data)) {
 		if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
 			datactrl |= MCI_DPSM_DMAENABLE;
@@ -1436,11 +1445,19 @@
 				}
 			}
 
+			/* Check for prog done */
+			if (host->curr.wait_for_auto_prog_done &&
+				(status & MCI_PROGDONE))
+				host->curr.got_auto_prog_done = 1;
+
 			/* Check for data done */
 			if (!host->curr.got_dataend && (status & MCI_DATAEND))
 				host->curr.got_dataend = 1;
 
-			if (host->curr.got_dataend) {
+			if (host->curr.got_dataend &&
+				(!host->curr.wait_for_auto_prog_done ||
+				(host->curr.wait_for_auto_prog_done &&
+				host->curr.got_auto_prog_done))) {
 				/*
 				 * If DMA is still in progress, we complete
 				 * via the completion handler
@@ -1541,14 +1558,23 @@
 
 	host->curr.mrq = mrq;
 
-	if (!host->plat->sdcc_v4_sup) {
-		if (mrq->data && mrq->data->flags == MMC_DATA_WRITE) {
-			if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
-				mrq->cmd->opcode == 54) {
+	if (mrq->data && mrq->data->flags == MMC_DATA_WRITE) {
+		if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
+			mrq->cmd->opcode == 54) {
+			if (!host->plat->sdcc_v4_sup)
 				host->dummy_52_needed = 1;
-			}
+			else
+				/*
+				 * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
+				 * write operations using CMD53 and CMD54.
+				 * Setting this bit with CMD53 would
+				 * automatically triggers PROG_DONE interrupt
+				 * without the need of sending dummy CMD52.
+				 */
+				host->curr.wait_for_auto_prog_done = 1;
 		}
 	}
+
 	msmsdcc_request_start(host, mrq);
 	spin_unlock_irqrestore(&host->lock, flags);
 }
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index f6f76ff..b4d2d58 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -77,6 +77,7 @@
 #define MCI_DPSM_DIRECTION	(1 << 1)
 #define MCI_DPSM_MODE		(1 << 2)
 #define MCI_DPSM_DMAENABLE	(1 << 3)
+#define MCI_AUTO_PROG_DONE	(1 << 19)
 #define MCI_RX_DATA_PEND	(1 << 20)
 
 #define MMCIDATACNT		0x030
@@ -256,6 +257,8 @@
 	unsigned int		xfer_remain;	/* Bytes remaining to send */
 	unsigned int		data_xfered;	/* Bytes acked by BLKEND irq */
 	int			got_dataend;
+	int			wait_for_auto_prog_done;
+	int			got_auto_prog_done;
 	int			user_pages;
 };