mmc: msm_sdcc: Driver clocking/irq improvements

- Clocks are now disabled after 1 second of inactivity
- Fixed issue which was causing us to loop through our ISR twice
- Bump core clock enable delay to 30us

Signed-off-by: San Mehat <san@google.com>
Signed-off-by: Daniel Walker <dwalker@codeaurora.org>
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 02bec7c..b4b6372 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -57,6 +57,32 @@
 #define PIO_SPINMAX 30
 #define CMD_SPINMAX 20
 
+
+static inline int
+msmsdcc_enable_clocks(struct msmsdcc_host *host, int enable)
+{
+	int rc;
+	WARN_ON(enable == host->clks_on);
+	if (enable) {
+		rc = clk_enable(host->pclk);
+		if (rc)
+			return rc;
+		rc = clk_enable(host->clk);
+		if (rc) {
+			clk_disable(host->pclk);
+			return rc;
+		}
+		udelay(30);
+		host->clks_on = 1;
+	} else {
+		clk_disable(host->clk);
+		clk_disable(host->pclk);
+		host->clks_on = 0;
+	}
+	return 0;
+}
+
+
 static void
 msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
 		      u32 c);
@@ -76,6 +102,8 @@
 	if (mrq->cmd->error == -ETIMEDOUT)
 		mdelay(5);
 
+	if (host->use_bustimer)
+		mod_timer(&host->busclk_timer, jiffies + HZ);
 	/*
 	 * Need to drop the host lock here; mmc_request_done may call
 	 * back into the driver...
@@ -676,6 +704,12 @@
 		status &= (readl(base + MMCIMASK0) | MCI_DATABLOCKENDMASK);
 		writel(status, base + MMCICLEAR);
 
+		if (status & MCI_SDIOINTR)
+			status &= ~MCI_SDIOINTR;
+
+		if (!status)
+			break;
+
 		msmsdcc_handle_irq_data(host, status, base);
 
 		if (status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
@@ -729,6 +763,8 @@
 	}
 
 	host->curr.mrq = mrq;
+	if (!host->clks_on)
+		msmsdcc_enable_clocks(host, 1);
 
 	if (mrq->data && mrq->data->flags & MMC_DATA_READ)
 		msmsdcc_start_data(host, mrq->data);
@@ -750,29 +786,6 @@
 	spin_unlock_irqrestore(&host->lock, flags);
 }
 
-static int inline
-msmsdcc_enable_clocks(struct msmsdcc_host *host, int enable)
-{
-	int rc;
-	if (enable) {
-		rc = clk_enable(host->pclk);
-		if (rc)
-			return rc;
-		rc = clk_enable(host->clk);
-		if (rc) {
-			clk_disable(host->pclk);
-			return rc;
-		}
-		host->clks_on = 1;
-		udelay(10);
-	} else {
-		clk_disable(host->clk);
-		clk_disable(host->pclk);
-		host->clks_on = 0;
-	}
-	return 0;
-}
-
 static void
 msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
@@ -782,10 +795,10 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&host->lock, flags);
-	if (ios->clock) {
+	if (!host->clks_on)
+		msmsdcc_enable_clocks(host, 1);
 
-		if (!host->clks_on)
-			msmsdcc_enable_clocks(host, 1);
+	if (ios->clock) {
 		if (ios->clock != host->clk_rate) {
 			rc = clk_set_rate(host->clk, ios->clock);
 			if (rc < 0)
@@ -829,8 +842,7 @@
 		host->pwr = pwr;
 		writel(pwr, host->base + MMCIPOWER);
 	}
-
-	if (!(clk & MCI_CLK_ENABLE) && host->clks_on)
+	if (host->clks_on)
 		msmsdcc_enable_clocks(host, 0);
 	spin_unlock_irqrestore(&host->lock, flags);
 }
@@ -909,6 +921,19 @@
 	msmsdcc_check_status((unsigned long) host);
 }
 
+static void
+msmsdcc_busclk_expired(unsigned long _data)
+{
+	struct msmsdcc_host	*host = (struct msmsdcc_host *) _data;
+	unsigned long 		flags;
+
+	spin_lock_irqsave(&host->lock, flags);
+	if (host->clks_on)
+		msmsdcc_enable_clocks(host, 0);
+
+	spin_unlock_irqrestore(&host->lock, flags);
+}
+
 /*
  * called when a command expires.
  * Dump some debugging, and then error
@@ -942,6 +967,8 @@
 	host->curr.mrq = NULL;
 	host->curr.cmd = NULL;
 
+	if (host->clks_on)
+		msmsdcc_enable_clocks(host, 0);
 	spin_unlock_irqrestore(&host->lock, flags);
 	mmc_request_done(host->mmc, mrq);
 }
@@ -1048,6 +1075,8 @@
 
 	host->cmdpoll = 1;
 
+	host->use_bustimer = 1;
+
 	host->base = ioremap(memres->start, PAGE_SIZE);
 	if (!host->base) {
 		ret = -ENOMEM;
@@ -1167,6 +1196,10 @@
 	host->command_timer.data = (unsigned long) host;
 	host->command_timer.function = msmsdcc_command_expired;
 
+	init_timer(&host->busclk_timer);
+	host->busclk_timer.data = (unsigned long) host;
+	host->busclk_timer.function = msmsdcc_busclk_expired;
+
 	ret = request_irq(cmd_irqres->start, msmsdcc_irq, IRQF_SHARED,
 			  DRIVER_NAME " (cmd)", host);
 	if (ret)
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index 8c84484..6846bd7 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -214,6 +214,8 @@
 	struct clk		*pclk;		/* SDCC peripheral bus clock */
 	unsigned int		clks_on;	/* set if clocks are enabled */
 	struct timer_list	command_timer;
+	struct timer_list	busclk_timer;
+	int			use_bustimer;
 
 	unsigned int		eject;		/* eject state */