ASoC: WCD9310: Add separate widgets for each spk amplifier

Add separate widgets for two external speakers amplifiers,
so that each speaker amplifier is turned off when the DAPM path for
that speaker in codec is powered off. This is needed to avoid pops
caused by having one combined external speaker widget turned off
after one of the codec DAPM paths is turned off.

Signed-off-by: Kiran Kandi <kkandi@codeaurora.org>
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index e93087c..45c0ceb 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -576,7 +576,7 @@
 	struct snd_soc_codec *codec = w->codec;
 	u16 lineout_gain_reg;
 
-	pr_debug("%s %d\n", __func__, event);
+	pr_debug("%s %d %s\n", __func__, event, w->name);
 
 	switch (w->shift) {
 	case 0:
@@ -605,6 +605,8 @@
 		snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
 		break;
 	case SND_SOC_DAPM_POST_PMU:
+		pr_debug("%s: sleeping 40 ms after %s PA turn on\n",
+				__func__, w->name);
 		usleep_range(40000, 40000);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
@@ -1024,21 +1026,25 @@
 		hphr_switch, ARRAY_SIZE(hphr_switch)),
 
 	/* Speaker */
-	SND_SOC_DAPM_OUTPUT("LINEOUT"),
+	SND_SOC_DAPM_OUTPUT("LINEOUT1"),
+	SND_SOC_DAPM_OUTPUT("LINEOUT2"),
+	SND_SOC_DAPM_OUTPUT("LINEOUT3"),
+	SND_SOC_DAPM_OUTPUT("LINEOUT4"),
+	SND_SOC_DAPM_OUTPUT("LINEOUT5"),
 
-	SND_SOC_DAPM_PGA_E("LINEOUT1", TABLA_A_RX_LINE_CNP_EN, 0, 0, NULL, 0,
-		tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_PGA_E("LINEOUT2", TABLA_A_RX_LINE_CNP_EN, 1, 0, NULL, 0,
-		tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_PGA_E("LINEOUT3", TABLA_A_RX_LINE_CNP_EN, 2, 0, NULL, 0,
-		tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_PGA_E("LINEOUT4", TABLA_A_RX_LINE_CNP_EN, 3, 0, NULL, 0,
-		tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
-		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-	SND_SOC_DAPM_PGA_E("LINEOUT5", TABLA_A_RX_LINE_CNP_EN, 4, 0, NULL, 0,
+	SND_SOC_DAPM_PGA_E("LINEOUT1 PA", TABLA_A_RX_LINE_CNP_EN, 0, 0, NULL,
+			0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
+			SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("LINEOUT2 PA", TABLA_A_RX_LINE_CNP_EN, 1, 0, NULL,
+			0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
+			SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("LINEOUT3 PA", TABLA_A_RX_LINE_CNP_EN, 2, 0, NULL,
+			0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
+			SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("LINEOUT4 PA", TABLA_A_RX_LINE_CNP_EN, 3, 0, NULL,
+			0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
+			SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("LINEOUT5 PA", TABLA_A_RX_LINE_CNP_EN, 4, 0, NULL, 0,
 		tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
@@ -1335,17 +1341,17 @@
 	{"HPHL DAC", "Switch", "RX1 CHAIN"},
 	{"HPHR DAC", "Switch", "RX2 CHAIN"},
 
-	{"LINEOUT", NULL, "LINEOUT1"},
-	{"LINEOUT", NULL, "LINEOUT2"},
-	{"LINEOUT", NULL, "LINEOUT3"},
-	{"LINEOUT", NULL, "LINEOUT4"},
-	{"LINEOUT", NULL, "LINEOUT5"},
+	{"LINEOUT1", NULL, "LINEOUT1 PA"},
+	{"LINEOUT2", NULL, "LINEOUT2 PA"},
+	{"LINEOUT3", NULL, "LINEOUT3 PA"},
+	{"LINEOUT4", NULL, "LINEOUT4 PA"},
+	{"LINEOUT5", NULL, "LINEOUT5 PA"},
 
-	{"LINEOUT1", NULL, "LINEOUT1 DAC"},
-	{"LINEOUT2", NULL, "LINEOUT2 DAC"},
-	{"LINEOUT3", NULL, "LINEOUT3 DAC"},
-	{"LINEOUT4", NULL, "LINEOUT4 DAC"},
-	{"LINEOUT5", NULL, "LINEOUT5 DAC"},
+	{"LINEOUT1 PA", NULL, "LINEOUT1 DAC"},
+	{"LINEOUT2 PA", NULL, "LINEOUT2 DAC"},
+	{"LINEOUT3 PA", NULL, "LINEOUT3 DAC"},
+	{"LINEOUT4 PA", NULL, "LINEOUT4 DAC"},
+	{"LINEOUT5 PA", NULL, "LINEOUT5 DAC"},
 
 	{"RX1 CHAIN", NULL, "RX1 MIX1"},
 	{"RX2 CHAIN", NULL, "RX2 MIX1"},
@@ -1364,6 +1370,7 @@
 	{"LINEOUT2 DAC", NULL, "RX_BIAS"},
 	{"LINEOUT3 DAC", NULL, "RX_BIAS"},
 	{"LINEOUT4 DAC", NULL, "RX_BIAS"},
+	{"LINEOUT5 DAC", NULL, "RX_BIAS"},
 
 	{"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
 	{"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index a61c0e7..edda550 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -11,6 +11,7 @@
  */
 
 #include <linux/clk.h>
+#include <linux/delay.h>
 #include <linux/gpio.h>
 #include <linux/mfd/pm8xxx/pm8921.h>
 #include <linux/platform_device.h>
@@ -31,8 +32,8 @@
 #define PM8921_GPIO_BASE		NR_GPIO_IRQS
 #define PM8921_GPIO_PM_TO_SYS(pm_gpio)  (pm_gpio - 1 + PM8921_GPIO_BASE)
 
-#define MSM_CDC_PAMPL (PM8921_GPIO_PM_TO_SYS(18))
-#define MSM_CDC_PAMPR (PM8921_GPIO_PM_TO_SYS(19))
+#define TOP_SPK_PAMP (PM8921_GPIO_PM_TO_SYS(18))
+#define BOTTOM_SPK_PAMP (PM8921_GPIO_PM_TO_SYS(19))
 #define MSM8960_SPK_ON 1
 #define MSM8960_SPK_OFF 0
 
@@ -43,7 +44,8 @@
 #define BTSCO_RATE_16KHZ 16000
 
 static int msm8960_spk_control;
-static int msm8960_pamp_on;
+static int msm8960_bottom_spk_pamp_on;
+static int msm8960_top_spk_pamp_on;
 static int msm8960_slim_0_rx_ch = 1;
 static int msm8960_slim_0_tx_ch = 1;
 
@@ -69,7 +71,7 @@
 static struct snd_soc_jack hs_jack;
 static struct snd_soc_jack button_jack;
 
-static void codec_poweramp_on(void)
+static void codec_poweramp_on(int bottom_spk)
 {
 	int ret = 0;
 
@@ -83,51 +85,71 @@
 		.function       = PM_GPIO_FUNC_NORMAL,
 	};
 
-	if (msm8960_pamp_on)
-		return;
+	if (bottom_spk) {
+		if (msm8960_bottom_spk_pamp_on)
+			return;
 
-	pr_debug("%s: enable stereo spkr amp\n", __func__);
-	ret = gpio_request(MSM_CDC_PAMPL, "CDC PAMP1");
-	if (ret) {
-		pr_err("%s: Error requesting GPIO %d\n", __func__,
-			MSM_CDC_PAMPL);
-		return;
+		ret = gpio_request(BOTTOM_SPK_PAMP, "BOTTOM_SPK_AMP");
+		if (ret) {
+			pr_err("%s: Error requesting GPIO %d\n", __func__,
+			BOTTOM_SPK_PAMP);
+			return;
+		}
+		ret = pm8xxx_gpio_config(BOTTOM_SPK_PAMP, &param);
+		if (ret)
+			pr_err("%s: Failed to configure gpio %d\n", __func__,
+				BOTTOM_SPK_PAMP);
+		else {
+			pr_debug("%s: enable Bottom spkr amp\n", __func__);
+			gpio_direction_output(BOTTOM_SPK_PAMP, 1);
+			msm8960_bottom_spk_pamp_on = 1;
+		}
+
+	} else {
+		if (msm8960_top_spk_pamp_on)
+			return;
+
+		ret = gpio_request(TOP_SPK_PAMP, "TOP_SPK_AMP");
+		if (ret) {
+			pr_err("%s: Error requesting GPIO %d\n", __func__,
+				TOP_SPK_PAMP);
+			return;
+		}
+		ret = pm8xxx_gpio_config(TOP_SPK_PAMP, &param);
+		if (ret)
+			pr_err("%s: Failed to configure gpio %d\n", __func__,
+				TOP_SPK_PAMP);
+		else {
+			pr_debug("%s: enable Top spkr amp\n", __func__);
+			gpio_direction_output(TOP_SPK_PAMP, 1);
+			msm8960_top_spk_pamp_on = 1;
+		}
 	}
-	ret = pm8xxx_gpio_config(MSM_CDC_PAMPL, &param);
-	if (ret)
-		pr_err("%s: Failed to configure gpio %d\n", __func__,
-			MSM_CDC_PAMPL);
-	else
-		gpio_direction_output(MSM_CDC_PAMPL, 1);
-
-	ret = gpio_request(MSM_CDC_PAMPR, "CDC PAMPL");
-	if (ret) {
-		pr_err("%s: Error requesting GPIO %d\n", __func__,
-			MSM_CDC_PAMPR);
-		gpio_free(MSM_CDC_PAMPL);
-		return;
-	}
-	ret = pm8xxx_gpio_config(MSM_CDC_PAMPR, &param);
-	if (ret)
-		pr_err("%s: Failed to configure gpio %d\n", __func__,
-			MSM_CDC_PAMPR);
-	else
-		gpio_direction_output(MSM_CDC_PAMPR, 1);
-
-	msm8960_pamp_on = 1;
+	pr_debug("%s: slepping 4 ms", __func__);
+	usleep_range(4000, 4000);
 }
-static void codec_poweramp_off(void)
+
+static void codec_poweramp_off(int bottom_spk)
 {
-	if (!msm8960_pamp_on)
-		return;
-
-	pr_debug("%s: disable stereo spkr amp\n", __func__);
-	gpio_direction_output(MSM_CDC_PAMPL, 0);
-	gpio_free(MSM_CDC_PAMPL);
-	gpio_direction_output(MSM_CDC_PAMPR, 0);
-	gpio_free(MSM_CDC_PAMPR);
-	msm8960_pamp_on = 0;
+	if (bottom_spk) {
+		if (!msm8960_bottom_spk_pamp_on)
+			return;
+		pr_debug("%s: disable Bottom spkr amp\n", __func__);
+		gpio_direction_output(BOTTOM_SPK_PAMP, 0);
+		gpio_free(BOTTOM_SPK_PAMP);
+		msm8960_bottom_spk_pamp_on = 0;
+	} else {
+		if (!msm8960_top_spk_pamp_on)
+			return;
+		pr_debug("%s: disable To spkr amp\n", __func__);
+		gpio_direction_output(TOP_SPK_PAMP, 0);
+		gpio_free(TOP_SPK_PAMP);
+		msm8960_top_spk_pamp_on = 0;
+	}
+	pr_debug("%s: slepping 4 ms", __func__);
+	usleep_range(4000, 4000);
 }
+
 static void msm8960_ext_control(struct snd_soc_codec *codec)
 {
 	struct snd_soc_dapm_context *dapm = &codec->dapm;
@@ -165,10 +187,18 @@
 	struct snd_kcontrol *k, int event)
 {
 	pr_debug("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event));
-	if (SND_SOC_DAPM_EVENT_ON(event))
-		codec_poweramp_on();
-	else
-		codec_poweramp_off();
+
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		if (!strncmp(w->name, "Ext Spk Bottom", 14))
+			codec_poweramp_on(1);
+		else
+			codec_poweramp_on(0);
+	} else {
+		if (!strncmp(w->name, "Ext Spk Bottom", 14))
+			codec_poweramp_off(1);
+		else
+			codec_poweramp_off(0);
+	}
 	return 0;
 }
 static int msm8960_mclk_enable_event(struct snd_soc_dapm_widget *w,
@@ -206,7 +236,6 @@
 
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMD:
-		pr_debug("%s: clk_users = %d\n", __func__, clk_users);
 
 		if (clk_users == 0)
 			return 0;
@@ -230,8 +259,9 @@
 	SND_SOC_DAPM_PRE("CODEC MCLK_ON", msm8960_mclk_enable_event),
 	SND_SOC_DAPM_POST("CODEC MCLK_OFF", msm8960_mclk_disable_event),
 
+	SND_SOC_DAPM_SPK("Ext Spk Bottom", msm8960_spkramp_event),
+	SND_SOC_DAPM_SPK("Ext Spk Top", msm8960_spkramp_event),
 
-	SND_SOC_DAPM_SPK("Ext Spk", msm8960_spkramp_event),
 	SND_SOC_DAPM_MIC("Handset Mic", NULL),
 	SND_SOC_DAPM_MIC("Headset Mic", NULL),
 	SND_SOC_DAPM_MIC("Digital Mic1", NULL),
@@ -249,7 +279,12 @@
 
 static const struct snd_soc_dapm_route common_audio_map[] = {
 	/* Speaker path */
-	{"Ext Spk", NULL, "LINEOUT"},
+
+	{"Ext Spk Bottom", NULL, "LINEOUT1"},
+	{"Ext Spk Bottom", NULL, "LINEOUT3"},
+
+	{"Ext Spk Top", NULL, "LINEOUT2"},
+	{"Ext Spk Top", NULL, "LINEOUT4"},
 
 	/* Microphone path */
 	{"AMIC1", NULL, "MIC BIAS1 Internal1"},