msm: rpm-regulator: Allow rpm_vreg_set_voltage voltage switch control

Modify the rpm-regulator driver so that rpm_vreg_set_voltage
supports voltage switch type regulators which do not have a
voltage setting.

For these types of regulators make rpm_vreg_set_voltage calls
map as follows:
1. max_uV  > 0 --> vote to enable the voltage switch
2. max_uV == 0 --> vote to disable the voltage switch

This modification is needed so that the acpuclock driver can call
rpm_vreg_set_voltage successfully for a voltage switch on the
APQ8064 platform.

Change-Id: Ibde2ded8fe578cb82e0a3bc28cdf046017583e06
Signed-off-by: David Collins <collinsd@codeaurora.org>
diff --git a/arch/arm/mach-msm/rpm-regulator.c b/arch/arm/mach-msm/rpm-regulator.c
index 946d31b..c472f94 100644
--- a/arch/arm/mach-msm/rpm-regulator.c
+++ b/arch/arm/mach-msm/rpm-regulator.c
@@ -268,8 +268,10 @@
 
 	if (vreg->part->uV.mask)
 		uV = GET_PART(vreg, uV);
-	else
+	else if (vreg->part->mV.mask)
 		uV = MILLI_TO_MICRO(GET_PART(vreg, mV));
+	else if (vreg->part->enable_state.mask)
+		uV = GET_PART(vreg, enable_state);
 
 	return uV;
 }
@@ -278,8 +280,10 @@
 {
 	if (vreg->part->uV.mask)
 		SET_PART(vreg, uV, uV);
-	else
+	else if (vreg->part->mV.mask)
 		SET_PART(vreg, mV, MICRO_TO_MILLI(uV));
+	else if (vreg->part->enable_state.mask)
+		SET_PART(vreg, enable_state, uV);
 }
 
 static int vreg_send_request(struct vreg *vreg, enum rpm_vreg_voter voter,
@@ -380,9 +384,14 @@
 		if (vreg->part->uV.mask) {
 			s_val[vreg->part->uV.word] = 0 << vreg->part->uV.shift;
 			s_mask[vreg->part->uV.word] = vreg->part->uV.mask;
-		} else {
+		} else if (vreg->part->mV.mask) {
 			s_val[vreg->part->mV.word] = 0 << vreg->part->mV.shift;
 			s_mask[vreg->part->mV.word] = vreg->part->mV.mask;
+		} else if (vreg->part->enable_state.mask) {
+			s_val[vreg->part->enable_state.word]
+				= 0 << vreg->part->enable_state.shift;
+			s_mask[vreg->part->enable_state.word]
+				= vreg->part->enable_state.mask;
 		}
 
 		rc = vreg_send_request(vreg, voter, MSM_RPM_CTX_SET_SLEEP,
@@ -421,6 +430,10 @@
  *
  * Consumers can vote to disable a regulator with this function by passing
  * min_uV = 0 and max_uV = 0.
+ *
+ * Voltage switch type regulators may be controlled via rpm_vreg_set_voltage
+ * as well.  For this type of regulator, max_uV > 0 is treated as an enable
+ * request and max_uV == 0 is treated as a disable request.
  */
 int rpm_vreg_set_voltage(int vreg_id, enum rpm_vreg_voter voter, int min_uV,
 			 int max_uV, int sleep_also)
@@ -450,7 +463,6 @@
 	}
 
 	vreg = &config->vregs[vreg_id];
-	range = &vreg->set_points->range[0];
 
 	if (!vreg->pdata.sleep_selectable) {
 		vreg_err(vreg, "regulator is not marked sleep selectable\n");
@@ -458,7 +470,8 @@
 	}
 
 	/* Allow min_uV == max_uV == 0 to represent a disable request. */
-	if (min_uV != 0 || max_uV != 0) {
+	if ((min_uV != 0 || max_uV != 0)
+	    && (vreg->part->uV.mask || vreg->part->mV.mask)) {
 		/*
 		 * Check if request voltage is outside of allowed range. The
 		 * regulator core has already checked that constraint range
@@ -477,6 +490,7 @@
 			return -EINVAL;
 		}
 
+		range = &vreg->set_points->range[0];
 		/* Find the range which uV is inside of. */
 		for (i = vreg->set_points->count - 1; i > 0; i--) {
 			if (uV > vreg->set_points->range[i - 1].max_uV) {
@@ -504,10 +518,20 @@
 	if (vreg->part->uV.mask) {
 		val[vreg->part->uV.word] = uV << vreg->part->uV.shift;
 		mask[vreg->part->uV.word] = vreg->part->uV.mask;
-	} else {
+	} else if (vreg->part->mV.mask) {
 		val[vreg->part->mV.word]
 			= MICRO_TO_MILLI(uV) << vreg->part->mV.shift;
 		mask[vreg->part->mV.word] = vreg->part->mV.mask;
+	} else if (vreg->part->enable_state.mask) {
+		/*
+		 * Translate max_uV > 0 into an enable request for regulator
+		 * types which to not support voltage setting, e.g. voltage
+		 * switches.
+		 */
+		val[vreg->part->enable_state.word]
+		    = (max_uV > 0 ? 1 : 0) << vreg->part->enable_state.shift;
+		mask[vreg->part->enable_state.word]
+		    = vreg->part->enable_state.mask;
 	}
 
 	rc = vreg_set_noirq(vreg, voter, sleep_also, mask[0], val[0], mask[1],