ASoC: wcd9xxx: Enhance class H controller to support dynamic CP voltage

Codecs can operate at a lower voltage for vdd_buck, whereas
this voltage source being shared, it is not guaranteed that the
codec will always receive exactly the requested voltage. Add support
to class H controller to handle dynamic switching of the chargepump
voltage.

Change-Id: I68f93e0b070ec51db9b958f56c797edb5cbe0c85
Signed-off-by: Bhalchandra Gajare <gajare@codeaurora.org>
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index b31c7c9..7b896c2 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -4273,6 +4273,12 @@
 	 */
 	TAPAN_REG_VAL(TAPAN_A_MICB_2_MBHC, 0x41),
 
+	/*
+	 * Default register settings to support dynamic change of
+	 * vdd_buck between 1.8 volts and 2.15 volts.
+	 */
+	TAPAN_REG_VAL(TAPAN_A_BUCK_MODE_2, 0xAA),
+
 };
 
 static const struct tapan_reg_mask_val tapan_2_x_reg_reset_values[] = {
@@ -4589,6 +4595,30 @@
 	return 0;
 }
 
+static enum wcd9xxx_buck_volt tapan_codec_get_buck_mv(
+	struct snd_soc_codec *codec)
+{
+	int buck_volt = WCD9XXX_CDC_BUCK_UNSUPPORTED;
+	struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
+	struct wcd9xxx_pdata *pdata = tapan->resmgr.pdata;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
+		if (!strncmp(pdata->regulator[i].name,
+					 WCD9XXX_SUPPLY_BUCK_NAME,
+					 sizeof(WCD9XXX_SUPPLY_BUCK_NAME))) {
+			if ((pdata->regulator[i].min_uV ==
+					WCD9XXX_CDC_BUCK_MV_1P8) ||
+				(pdata->regulator[i].min_uV ==
+					WCD9XXX_CDC_BUCK_MV_2P15))
+				buck_volt = pdata->regulator[i].min_uV;
+			break;
+		}
+	}
+	pr_debug("%s: S4 voltage requested is %d\n", __func__, buck_volt);
+	return buck_volt;
+}
+
 static int tapan_codec_probe(struct snd_soc_codec *codec)
 {
 	struct wcd9xxx *control;
@@ -4621,10 +4651,6 @@
 
 	snd_soc_codec_set_drvdata(codec, tapan);
 
-	/* TODO: Read buck voltage from DT property */
-	tapan->clsh_d.buck_mv = WCD9XXX_CDC_BUCK_MV_1P8;
-	wcd9xxx_clsh_init(&tapan->clsh_d, &tapan->resmgr);
-
 	/* codec resmgr module init */
 	wcd9xxx = codec->control_data;
 	pdata = dev_get_platdata(codec->dev->parent);
@@ -4635,6 +4661,16 @@
 		return ret;
 	}
 
+	tapan->clsh_d.buck_mv = tapan_codec_get_buck_mv(codec);
+	/*
+	 * If 1.8 volts is requested on the vdd_cp line, then
+	 * assume that S4 is in a dynamically switchable state
+	 * and can switch between 1.8 volts and 2.15 volts
+	 */
+	if (tapan->clsh_d.buck_mv == WCD9XXX_CDC_BUCK_MV_1P8)
+		tapan->clsh_d.is_dynamic_vdd_cp = true;
+	wcd9xxx_clsh_init(&tapan->clsh_d, &tapan->resmgr);
+
 	if (TAPAN_IS_1_0(control->version))
 		rco_clk_rate = TAPAN_MCLK_CLK_12P288MHZ;
 	else
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 516ac4f..611a293 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -6389,6 +6389,8 @@
 	}
 
 	taiko->clsh_d.buck_mv = taiko_codec_get_buck_mv(codec);
+	/* Taiko does not support dynamic switching of vdd_cp */
+	taiko->clsh_d.is_dynamic_vdd_cp = false;
 	wcd9xxx_clsh_init(&taiko->clsh_d, &taiko->resmgr);
 
 	if (TAIKO_IS_1_0(core->version))
diff --git a/sound/soc/codecs/wcd9xxx-common.c b/sound/soc/codecs/wcd9xxx-common.c
index 916ff1a..b89afa9 100644
--- a/sound/soc/codecs/wcd9xxx-common.c
+++ b/sound/soc/codecs/wcd9xxx-common.c
@@ -221,20 +221,26 @@
 	usleep_range(BUCK_SETTLE_TIME_US, BUCK_SETTLE_TIME_US);
 }
 
-static void wcd9xxx_clsh_enable_post_pa(struct snd_soc_codec *codec)
+
+/* This will be called for all states except Lineout */
+static void wcd9xxx_clsh_enable_post_pa(struct snd_soc_codec *codec,
+	struct wcd9xxx_clsh_cdc_data *cdc_clsh_d)
 {
 	int i;
 	const struct wcd9xxx_reg_mask_val reg_set[] = {
 		{WCD9XXX_A_BUCK_MODE_5, 0x02, 0x00},
 		{WCD9XXX_A_NCP_STATIC, 0x20, 0x00},
 		{WCD9XXX_A_BUCK_MODE_3, 0x04, 0x04},
-		{WCD9XXX_A_BUCK_MODE_3, 0x08, 0x08},
 	};
 
 	for (i = 0; i < ARRAY_SIZE(reg_set); i++)
 		snd_soc_update_bits(codec, reg_set[i].reg,
 					reg_set[i].mask, reg_set[i].val);
 
+	if (!cdc_clsh_d->is_dynamic_vdd_cp)
+		snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_3,
+							0x08, 0x08);
+
 	dev_dbg(codec->dev, "%s: completed clsh mode settings after PA enable\n",
 		   __func__);
 
@@ -557,7 +563,7 @@
 
 
 		} else if (req_state != WCD9XXX_CLSH_STATE_LO) {
-			wcd9xxx_clsh_enable_post_pa(codec);
+			wcd9xxx_clsh_enable_post_pa(codec, cdc_clsh_d);
 		}
 
 		break;
diff --git a/sound/soc/codecs/wcd9xxx-common.h b/sound/soc/codecs/wcd9xxx-common.h
index 316742d..50381c9 100644
--- a/sound/soc/codecs/wcd9xxx-common.h
+++ b/sound/soc/codecs/wcd9xxx-common.h
@@ -52,6 +52,7 @@
 struct wcd9xxx_clsh_cdc_data {
 	u8 state;
 	int buck_mv;
+	bool is_dynamic_vdd_cp;
 	struct wcd9xxx_resmgr *resmgr;
 };