mmc: msm_sdcc: set low voltage for VDD pad rail during sleep

As VDD pad rail is always on, set low voltage for VDD pad rail
during sleep (when card is not present or during system suspend).
This will help to save the leakage current during sleep.

Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
diff --git a/arch/arm/include/asm/mach/mmc.h b/arch/arm/include/asm/mach/mmc.h
index d439160..4c2e970 100644
--- a/arch/arm/include/asm/mach/mmc.h
+++ b/arch/arm/include/asm/mach/mmc.h
@@ -28,7 +28,8 @@
 	/* regulator name */
 	const char *name;
 	/* voltage level to be set */
-	unsigned int level;
+	unsigned int low_vol_level;
+	unsigned int high_vol_level;
 	/* Load values for low power and high power mode */
 	unsigned int lpm_uA;
 	unsigned int hpm_uA;
diff --git a/arch/arm/mach-msm/board-msm8960.c b/arch/arm/mach-msm/board-msm8960.c
index adbfff7..9db8593 100644
--- a/arch/arm/mach-msm/board-msm8960.c
+++ b/arch/arm/mach-msm/board-msm8960.c
@@ -1967,14 +1967,16 @@
 	[SDCC1] = {
 		.name = "sdc_vdd",
 		.set_voltage_sup = 1,
-		.level = 2950000,
+		.high_vol_level = 2950000,
+		.low_vol_level = 2950000,
 		.hpm_uA = 200000, /* 200mA */
 	},
 	/* SDCC3 : External card slot connected */
 	[SDCC3] = {
 		.name = "sdc_vdd",
 		.set_voltage_sup = 1,
-		.level = 2950000,
+		.high_vol_level = 2950000,
+		.low_vol_level = 2950000,
 		.hpm_uA = 600000, /* 600mA */
 	}
 };
@@ -1986,7 +1988,8 @@
 		.name = "sdc_vccq",
 		.set_voltage_sup = 1,
 		.always_on = 1,
-		.level = 1800000,
+		.high_vol_level = 1800000,
+		.low_vol_level = 1800000,
 		.hpm_uA = 200000, /* 200mA */
 	}
 };
@@ -1997,7 +2000,8 @@
 	[SDCC3] = {
 		.name = "sdc_vddp",
 		.set_voltage_sup = 1,
-		.level = 2950000,
+		.high_vol_level = 2950000,
+		.low_vol_level = 1850000,
 		.always_on = 1,
 		.lpm_sup = 1,
 		/* Max. Active current required is 16 mA */
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 7d7e431..274b5b1 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -1675,8 +1675,8 @@
 
 	if (!vreg->is_enabled) {
 		/* Set voltage level */
-		rc = msmsdcc_vreg_set_voltage(vreg, vreg->level,
-						vreg->level);
+		rc = msmsdcc_vreg_set_voltage(vreg, vreg->high_vol_level,
+						vreg->high_vol_level);
 		if (rc)
 			goto out;
 
@@ -1712,7 +1712,7 @@
 			goto out;
 
 		/* Set min. voltage level to 0 */
-		rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->level);
+		rc = msmsdcc_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
 		if (rc)
 			goto out;
 	} else if (vreg->is_enabled && vreg->always_on && vreg->lpm_sup) {
@@ -1754,7 +1754,7 @@
 	return rc;
 }
 
-static int msmsdcc_tune_vdd_pad_level(struct msmsdcc_host *host, int level)
+static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
 {
 	int rc = 0;
 
@@ -1769,6 +1769,42 @@
 	return rc;
 }
 
+static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
+{
+	struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
+	int rc = 0;
+
+	if (curr_slot && curr_slot->vddp_data) {
+		rc = msmsdcc_set_vddp_level(host,
+			curr_slot->vddp_data->low_vol_level);
+
+		if (rc)
+			pr_err("%s: %s: failed to change vddp level to %d",
+				mmc_hostname(host->mmc), __func__,
+				curr_slot->vddp_data->low_vol_level);
+	}
+
+	return rc;
+}
+
+static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
+{
+	struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
+	int rc = 0;
+
+	if (curr_slot && curr_slot->vddp_data) {
+		rc = msmsdcc_set_vddp_level(host,
+			curr_slot->vddp_data->high_vol_level);
+
+		if (rc)
+			pr_err("%s: %s: failed to change vddp level to %d",
+				mmc_hostname(host->mmc), __func__,
+				curr_slot->vddp_data->high_vol_level);
+	}
+
+	return rc;
+}
+
 static inline int msmsdcc_is_pwrsave(struct msmsdcc_host *host)
 {
 	if (host->clk_rate > 400000 && msmsdcc_pwrsave)
@@ -2071,6 +2107,12 @@
 			disable_irq(host->core_irqres->start);
 			host->sdcc_irq_disabled = 1;
 		}
+		/*
+		 * As VDD pad rail is always on, set low voltage for VDD
+		 * pad rail when slot is unused (when card is not present
+		 * or during system suspend).
+		 */
+		msmsdcc_set_vddp_low_vol(host);
 		msmsdcc_setup_pins(host, false);
 		break;
 	case MMC_POWER_UP:
@@ -2082,6 +2124,7 @@
 			enable_irq(host->core_irqres->start);
 			host->sdcc_irq_disabled = 0;
 		}
+		msmsdcc_set_vddp_high_vol(host);
 		msmsdcc_setup_pins(host, true);
 		break;
 	case MMC_POWER_ON:
@@ -2265,17 +2308,15 @@
 {
 	struct msmsdcc_host *host = mmc_priv(mmc);
 	unsigned long flags;
-	int err = 0;
+	int rc = 0;
 
 	if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
 		/* Change voltage level of VDDPX to high voltage */
-		if (msmsdcc_tune_vdd_pad_level(host, 2950000)) {
-			pr_err("%s: %s: failed to change vddp level to %d",
-				mmc_hostname(mmc), __func__, 2950000);
-		}
+		rc = msmsdcc_set_vddp_high_vol(host);
 		goto out;
 	} else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
 		/* invalid selection. don't do anything */
+		rc = -EINVAL;
 		goto out;
 	}
 
@@ -2290,7 +2331,7 @@
 	 * register until they become all zeros.
 	 */
 	if (readl_relaxed(host->base + MCI_TEST_INPUT) & (0xF << 1)) {
-		err = -EAGAIN;
+		rc = -EAGAIN;
 		pr_err("%s: %s: MCIDATIN_3_0 is still not all zeros",
 			mmc_hostname(mmc), __func__);
 		goto out_unlock;
@@ -2306,11 +2347,9 @@
 	 * Switch VDDPX from high voltage to low voltage
 	 * to change the VDD of the SD IO pads.
 	 */
-	if (msmsdcc_tune_vdd_pad_level(host, 1850000)) {
-		pr_err("%s: %s: failed to change vddp level to %d",
-			mmc_hostname(mmc), __func__, 1850000);
+	rc = msmsdcc_set_vddp_low_vol(host);
+	if (rc)
 		goto out;
-	}
 
 	spin_lock_irqsave(&host->lock, flags);
 	writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
@@ -2340,14 +2379,14 @@
 				!= (0xF << 1)) {
 		pr_err("%s: %s: MCIDATIN_3_0 are still not all ones",
 			mmc_hostname(mmc), __func__);
-		err = -EAGAIN;
+		rc = -EAGAIN;
 		goto out_unlock;
 	}
 
 out_unlock:
 	spin_unlock_irqrestore(&host->lock, flags);
 out:
-	return err;
+	return rc;
 }
 
 static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,