msm: rpm-regulator: allow disabling via rpm_vreg_set_voltage

Provide a means for consumers to vote to disable a regulator
using the rpm_vreg_set_voltage API.  Change the constraint
checking so that min_uV = max_uV = 0 becomes a disable request.

Change-Id: Ibaa8b862e9591228dbb9d17eaf61d91e07574069
Signed-off-by: David Collins <collinsd@codeaurora.org>
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator.h b/arch/arm/mach-msm/include/mach/rpm-regulator.h
index 8b5a1e7..7ffa2985 100644
--- a/arch/arm/mach-msm/include/mach/rpm-regulator.h
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator.h
@@ -155,6 +155,9 @@
  *
  * This function may only be called for regulators which have the sleep flag
  * specified in their private data.
+ *
+ * Consumers can vote to disable a regulator with this function by passing
+ * min_uV = 0 and max_uV = 0.
  */
 int rpm_vreg_set_voltage(int vreg_id, enum rpm_vreg_voter voter, int min_uV,
 			 int max_uV, int sleep_also);
diff --git a/arch/arm/mach-msm/rpm-regulator.c b/arch/arm/mach-msm/rpm-regulator.c
index 2494969..5c2bb8e 100644
--- a/arch/arm/mach-msm/rpm-regulator.c
+++ b/arch/arm/mach-msm/rpm-regulator.c
@@ -416,6 +416,9 @@
  *
  * This function may only be called for regulators which have the sleep flag
  * specified in their private data.
+ *
+ * Consumers can vote to disable a regulator with this function by passing
+ * min_uV = 0 and max_uV = 0.
  */
 int rpm_vreg_set_voltage(int vreg_id, enum rpm_vreg_voter voter, int min_uV,
 			 int max_uV, int sleep_also)
@@ -452,38 +455,41 @@
 		return -EINVAL;
 	}
 
-	/*
-	 * Check if request voltage is outside of allowed range. The regulator
-	 * core has already checked that constraint range is inside of the
-	 * physically allowed range.
-	 */
-	lim_min_uV = vreg->pdata.init_data.constraints.min_uV;
-	lim_max_uV = vreg->pdata.init_data.constraints.max_uV;
+	/* Allow min_uV == max_uV == 0 to represent a disable request. */
+	if (min_uV != 0 || max_uV != 0) {
+		/*
+		 * Check if request voltage is outside of allowed range. The
+		 * regulator core has already checked that constraint range
+		 * is inside of the physically allowed range.
+		 */
+		lim_min_uV = vreg->pdata.init_data.constraints.min_uV;
+		lim_max_uV = vreg->pdata.init_data.constraints.max_uV;
 
-	if (uV < lim_min_uV && max_uV >= lim_min_uV)
-		uV = lim_min_uV;
+		if (uV < lim_min_uV && max_uV >= lim_min_uV)
+			uV = lim_min_uV;
 
-	if (uV < lim_min_uV || uV > lim_max_uV) {
-		vreg_err(vreg,
-			"request v=[%d, %d] is outside allowed v=[%d, %d]\n",
-			 min_uV, max_uV, lim_min_uV, lim_max_uV);
-		return -EINVAL;
-	}
-
-	/* 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) {
-			range = &vreg->set_points->range[i];
-			break;
+		if (uV < lim_min_uV || uV > lim_max_uV) {
+			vreg_err(vreg, "request v=[%d, %d] is outside allowed "
+				"v=[%d, %d]\n", min_uV, max_uV, lim_min_uV,
+				lim_max_uV);
+			return -EINVAL;
 		}
-	}
 
-	/*
-	 * Force uV to be an allowed set point and apply a ceiling function
-	 * to non-set point values.
-	 */
-	uV = (uV - range->min_uV + range->step_uV - 1) / range->step_uV;
-	uV = uV * range->step_uV + range->min_uV;
+		/* 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) {
+				range = &vreg->set_points->range[i];
+				break;
+			}
+		}
+
+		/*
+		 * Force uV to be an allowed set point and apply a ceiling
+		 * function to non-set point values.
+		 */
+		uV = (uV - range->min_uV + range->step_uV - 1) / range->step_uV;
+		uV = uV * range->step_uV + range->min_uV;
+	}
 
 	if (vreg->part->uV.mask) {
 		val[vreg->part->uV.word] = uV << vreg->part->uV.shift;