Merge "ASoC: wcd9xxx: Add support on-demand supplies"
diff --git a/Documentation/devicetree/bindings/sound/taiko_codec.txt b/Documentation/devicetree/bindings/sound/taiko_codec.txt
index a18747f..bad7b85 100644
--- a/Documentation/devicetree/bindings/sound/taiko_codec.txt
+++ b/Documentation/devicetree/bindings/sound/taiko_codec.txt
@@ -71,6 +71,11 @@
 			 values for 9.6MHZ mclk can be 2400000 Hz, 3200000 Hz
 			 and 4800000 Hz.  The values for 12.288MHz mclk can be
 			 3072200 Hz, 4096000 Hz and 6144000 Hz.
+
+ - qcom,cdc-on-demand-supplies: List of supplies which can be enabled
+				dynamically.
+				Supplies in this list are off by default.
+
 Example:
 
 taiko_codec {
@@ -115,6 +120,8 @@
 				   "cdc-vddcx-1",
 				   "cdc-vddcx-2";
 
+	com,cdc-on-demand-supplies = "cdc-vdd-spkdrv";
+
 	qcom,cdc-micbias-ldoh-v = <0x3>;
 	qcom,cdc-micbias-cfilt1-mv = <1800>;
 	qcom,cdc-micbias-cfilt2-mv = <2700>;
@@ -195,6 +202,12 @@
  - qcom,cdc-mclk-clk-rate - Specifies the master clock rate in Hz required for
 			    codec.
 
+Optional properties:
+
+ - qcom,cdc-on-demand-supplies: List of supplies which can be enabled
+				dynamically.
+				Supplies in this list are off by default.
+
 Example:
 i2c@f9925000 {
 	cell-index = <3>;
@@ -252,6 +265,8 @@
 					   "cdc-vddcx-1",
 					   "cdc-vddcx-2";
 
+		com,cdc-on-demand-supplies = "cdc-vdd-spkdrv";
+
 		qcom,cdc-micbias-ldoh-v = <0x3>;
 		qcom,cdc-micbias-cfilt1-mv = <1800>;
 		qcom,cdc-micbias-cfilt2-mv = <2700>;
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index e0af5d3..046faac 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -58,7 +58,8 @@
 };
 
 static int wcd9xxx_dt_parse_vreg_info(struct device *dev,
-	struct wcd9xxx_regulator *vreg, const char *vreg_name);
+				      struct wcd9xxx_regulator *vreg,
+				      const char *vreg_name, bool ondemand);
 static int wcd9xxx_dt_parse_micbias_info(struct device *dev,
 	struct wcd9xxx_micbias_setting *micbias);
 static struct wcd9xxx_pdata *wcd9xxx_populate_dt_pdata(struct device *dev);
@@ -623,8 +624,8 @@
 };
 #endif
 
-static int wcd9xxx_enable_supplies(struct wcd9xxx *wcd9xxx,
-				struct wcd9xxx_pdata *pdata)
+static int wcd9xxx_init_supplies(struct wcd9xxx *wcd9xxx,
+				 struct wcd9xxx_pdata *pdata)
 {
 	int ret;
 	int i;
@@ -638,7 +639,7 @@
 
 	wcd9xxx->num_of_supplies = 0;
 
-	if (ARRAY_SIZE(pdata->regulator) > MAX_REGULATOR) {
+	if (ARRAY_SIZE(pdata->regulator) > WCD9XXX_MAX_REGULATOR) {
 		pr_err("%s: Array Size out of bound\n", __func__);
 		ret = -EINVAL;
 		goto err;
@@ -660,8 +661,12 @@
 	}
 
 	for (i = 0; i < wcd9xxx->num_of_supplies; i++) {
+		if (regulator_count_voltages(wcd9xxx->supplies[i].consumer) <=
+		    0)
+			continue;
 		ret = regulator_set_voltage(wcd9xxx->supplies[i].consumer,
-			pdata->regulator[i].min_uV, pdata->regulator[i].max_uV);
+					    pdata->regulator[i].min_uV,
+					    pdata->regulator[i].max_uV);
 		if (ret) {
 			pr_err("%s: Setting regulator voltage failed for "
 				"regulator %s err = %d\n", __func__,
@@ -670,30 +675,19 @@
 		}
 
 		ret = regulator_set_optimum_mode(wcd9xxx->supplies[i].consumer,
-			pdata->regulator[i].optimum_uA);
+						pdata->regulator[i].optimum_uA);
 		if (ret < 0) {
 			pr_err("%s: Setting regulator optimum mode failed for "
 				"regulator %s err = %d\n", __func__,
 				wcd9xxx->supplies[i].supply, ret);
 			goto err_get;
+		} else {
+			ret = 0;
 		}
 	}
 
-	ret = regulator_bulk_enable(wcd9xxx->num_of_supplies,
-				    wcd9xxx->supplies);
-	if (ret != 0) {
-		dev_err(wcd9xxx->dev, "Failed to enable supplies: err = %d\n",
-				ret);
-		goto err_configure;
-	}
 	return ret;
 
-err_configure:
-	for (i = 0; i < wcd9xxx->num_of_supplies; i++) {
-		regulator_set_voltage(wcd9xxx->supplies[i].consumer, 0,
-			pdata->regulator[i].max_uV);
-		regulator_set_optimum_mode(wcd9xxx->supplies[i].consumer, 0);
-	}
 err_get:
 	regulator_bulk_free(wcd9xxx->num_of_supplies, wcd9xxx->supplies);
 err_supplies:
@@ -702,6 +696,33 @@
 	return ret;
 }
 
+static int wcd9xxx_enable_static_supplies(struct wcd9xxx *wcd9xxx,
+					  struct wcd9xxx_pdata *pdata)
+{
+	int i;
+	int ret = 0;
+
+	for (i = 0; i < wcd9xxx->num_of_supplies; i++) {
+		if (pdata->regulator[i].ondemand)
+			continue;
+		ret = regulator_enable(wcd9xxx->supplies[i].consumer);
+		if (ret) {
+			pr_err("%s: Failed to enable %s\n", __func__,
+			       wcd9xxx->supplies[i].supply);
+			break;
+		} else {
+			pr_debug("%s: Enabled regulator %s\n", __func__,
+				 wcd9xxx->supplies[i].supply);
+		}
+	}
+
+	while (ret && --i)
+		if (!pdata->regulator[i].ondemand)
+			regulator_disable(wcd9xxx->supplies[i].consumer);
+
+	return ret;
+}
+
 static void wcd9xxx_disable_supplies(struct wcd9xxx *wcd9xxx,
 				     struct wcd9xxx_pdata *pdata)
 {
@@ -710,8 +731,11 @@
 	regulator_bulk_disable(wcd9xxx->num_of_supplies,
 				    wcd9xxx->supplies);
 	for (i = 0; i < wcd9xxx->num_of_supplies; i++) {
+		if (regulator_count_voltages(wcd9xxx->supplies[i].consumer) <=
+		    0)
+			continue;
 		regulator_set_voltage(wcd9xxx->supplies[i].consumer, 0,
-			pdata->regulator[i].max_uV);
+				      pdata->regulator[i].max_uV);
 		regulator_set_optimum_mode(wcd9xxx->supplies[i].consumer, 0);
 	}
 	regulator_bulk_free(wcd9xxx->num_of_supplies, wcd9xxx->supplies);
@@ -930,18 +954,26 @@
 		wcd9xxx->slim_device_bootup = true;
 		if (client->dev.of_node)
 			wcd9xxx->mclk_rate = pdata->mclk_rate;
-		ret = wcd9xxx_enable_supplies(wcd9xxx, pdata);
+
+		ret = wcd9xxx_init_supplies(wcd9xxx, pdata);
 		if (ret) {
 			pr_err("%s: Fail to enable Codec supplies\n",
 			       __func__);
 			goto err_codec;
 		}
 
+		ret = wcd9xxx_enable_static_supplies(wcd9xxx, pdata);
+		if (ret) {
+			pr_err("%s: Fail to enable Codec pre-reset supplies\n",
+			       __func__);
+			goto err_codec;
+		}
 		usleep_range(5, 5);
+
 		ret = wcd9xxx_reset(wcd9xxx);
 		if (ret) {
 			pr_err("%s: Resetting Codec failed\n", __func__);
-		goto err_supplies;
+			goto err_supplies;
 		}
 
 		ret = wcd9xxx_i2c_get_client_index(client, &wcd9xx_index);
@@ -1001,7 +1033,9 @@
 }
 
 static int wcd9xxx_dt_parse_vreg_info(struct device *dev,
-	struct wcd9xxx_regulator *vreg, const char *vreg_name)
+				      struct wcd9xxx_regulator *vreg,
+				      const char *vreg_name,
+				      bool ondemand)
 {
 	int len, ret = 0;
 	const __be32 *prop;
@@ -1019,6 +1053,7 @@
 		return -ENODEV;
 	}
 	vreg->name = vreg_name;
+	vreg->ondemand = ondemand;
 
 	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
 		"qcom,%s-voltage", vreg_name);
@@ -1027,7 +1062,7 @@
 	if (!prop || (len != (2 * sizeof(__be32)))) {
 		dev_err(dev, "%s %s property\n",
 				prop ? "invalid format" : "no", prop_name);
-		return -ENODEV;
+		return -EINVAL;
 	} else {
 		vreg->min_uV = be32_to_cpup(&prop[0]);
 		vreg->max_uV = be32_to_cpup(&prop[1]);
@@ -1040,12 +1075,12 @@
 	if (ret) {
 		dev_err(dev, "Looking up %s property in node %s failed",
 				prop_name, dev->of_node->full_name);
-		return -ENODEV;
+		return -EFAULT;
 	}
 	vreg->optimum_uA = prop_val;
 
-	dev_info(dev, "%s: vol=[%d %d]uV, curr=[%d]uA\n", vreg->name,
-		vreg->min_uV, vreg->max_uV, vreg->optimum_uA);
+	dev_info(dev, "%s: vol=[%d %d]uV, curr=[%d]uA, ond %d\n", vreg->name,
+		vreg->min_uV, vreg->max_uV, vreg->optimum_uA, vreg->ondemand);
 	return 0;
 }
 
@@ -1163,11 +1198,12 @@
 static struct wcd9xxx_pdata *wcd9xxx_populate_dt_pdata(struct device *dev)
 {
 	struct wcd9xxx_pdata *pdata;
-	int ret, static_cnt, i;
+	int ret, static_cnt, ond_cnt, idx, i;
 	const char *name = NULL;
 	u32 mclk_rate = 0;
 	u32 dmic_sample_rate = 0;
 	const char *static_prop_name = "qcom,cdc-static-supplies";
+	const char *ond_prop_name = "qcom,cdc-on-demand-supplies";
 
 	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
 	if (!pdata) {
@@ -1182,25 +1218,46 @@
 		goto err;
 	}
 
-	if (static_cnt > ARRAY_SIZE(pdata->regulator)) {
+	/* On-demand supply list is an optional property */
+	ond_cnt = of_property_count_strings(dev->of_node, ond_prop_name);
+	if (IS_ERR_VALUE(ond_cnt))
+		ond_cnt = 0;
+
+	BUG_ON(static_cnt <= 0 || ond_cnt < 0);
+	if ((static_cnt + ond_cnt) > ARRAY_SIZE(pdata->regulator)) {
 		dev_err(dev, "%s: Num of supplies %u > max supported %u\n",
 			__func__, static_cnt, ARRAY_SIZE(pdata->regulator));
 		goto err;
 	}
 
-	for (i = 0; i < static_cnt; i++) {
+	for (idx = 0; idx < static_cnt; idx++) {
 		ret = of_property_read_string_index(dev->of_node,
-						    static_prop_name, i, &name);
+						    static_prop_name, idx,
+						    &name);
 		if (ret) {
 			dev_err(dev, "%s: of read string %s idx %d error %d\n",
-				__func__, static_prop_name, i, ret);
+				__func__, static_prop_name, idx, ret);
 			goto err;
 		}
 
 		dev_dbg(dev, "%s: Found static cdc supply %s\n", __func__,
 			name);
-		ret = wcd9xxx_dt_parse_vreg_info(dev, &pdata->regulator[i],
-						 name);
+		ret = wcd9xxx_dt_parse_vreg_info(dev, &pdata->regulator[idx],
+						 name, false);
+		if (ret)
+			goto err;
+	}
+
+	for (i = 0; i < ond_cnt; i++, idx++) {
+		ret = of_property_read_string_index(dev->of_node, ond_prop_name,
+						    i, &name);
+		if (ret)
+			goto err;
+
+		dev_dbg(dev, "%s: Found on-demand cdc supply %s\n", __func__,
+			name);
+		ret = wcd9xxx_dt_parse_vreg_info(dev, &pdata->regulator[idx],
+						 name, true);
 		if (ret)
 			goto err;
 	}
@@ -1342,9 +1399,17 @@
 	wcd9xxx->mclk_rate = pdata->mclk_rate;
 	wcd9xxx->slim_device_bootup = true;
 
-	ret = wcd9xxx_enable_supplies(wcd9xxx, pdata);
-	if (ret)
+	ret = wcd9xxx_init_supplies(wcd9xxx, pdata);
+	if (ret) {
+		pr_err("%s: Fail to init Codec supplies %d\n", __func__, ret);
 		goto err_codec;
+	}
+	ret = wcd9xxx_enable_static_supplies(wcd9xxx, pdata);
+	if (ret) {
+		pr_err("%s: Fail to enable Codec pre-reset supplies\n",
+		       __func__);
+		goto err_codec;
+	}
 	usleep_range(5, 5);
 
 	ret = wcd9xxx_reset(wcd9xxx);
diff --git a/include/linux/mfd/wcd9xxx/pdata.h b/include/linux/mfd/wcd9xxx/pdata.h
index 813cac3..ec7139c 100644
--- a/include/linux/mfd/wcd9xxx/pdata.h
+++ b/include/linux/mfd/wcd9xxx/pdata.h
@@ -136,7 +136,7 @@
 	unsigned int	hph_ocp_limit:3; /* Headphone OCP current limit */
 };
 
-#define MAX_REGULATOR	7
+#define WCD9XXX_MAX_REGULATOR	8
 /*
  *      format : TABLA_<POWER_SUPPLY_PIN_NAME>_CUR_MAX
  *
@@ -156,6 +156,7 @@
 	int min_uV;
 	int max_uV;
 	int optimum_uA;
+	bool ondemand;
 	struct regulator *regulator;
 };
 
@@ -168,7 +169,7 @@
 	struct slim_device slimbus_slave_device;
 	struct wcd9xxx_micbias_setting micbias;
 	struct wcd9xxx_ocp_setting ocp;
-	struct wcd9xxx_regulator regulator[MAX_REGULATOR];
+	struct wcd9xxx_regulator regulator[WCD9XXX_MAX_REGULATOR];
 	u32 mclk_rate;
 	u32 dmic_sample_rate;
 };