From e122cbe7e2cb1492abd34fc42c57f8da4f8112e2 Mon Sep 17 00:00:00 2001
From: =?utf8?q?=E9=99=88=E9=87=91=E6=B3=89?= <chenjq@rock-chips.com>
Date: Fri, 30 Aug 2013 10:59:14 +0800
Subject: [PATCH] rk616 codec: add control for modem incall pop noise

---
 sound/soc/codecs/rk616_codec.c | 83 +++++++++++++++-------------------
 1 file changed, 37 insertions(+), 46 deletions(-)

diff --git a/sound/soc/codecs/rk616_codec.c b/sound/soc/codecs/rk616_codec.c
index a1aeddc31ac5..4afc4b1a9aba 100755
--- a/sound/soc/codecs/rk616_codec.c
+++ b/sound/soc/codecs/rk616_codec.c
@@ -719,11 +719,15 @@ static int rk616_codec_power_up(int type)
 		type == RK616_CODEC_CAPTURE ? "capture" : "",
 		type == RK616_CODEC_INCALL ? "incall" : "");
 
-	if (type == RK616_CODEC_PLAYBACK) {
-		// mute output for pop noise
+	// mute output for pop noise
+	if (type == RK616_CODEC_PLAYBACK ||
+		type == RK616_CODEC_INCALL ||
+		type == RK616_CODEC_ALL) {
 		rk616_set_gpio(RK616_CODEC_SET_SPK, GPIO_LOW);
 		rk616_set_gpio(RK616_CODEC_SET_HP, GPIO_LOW);
+	}
 
+	if (type == RK616_CODEC_PLAYBACK) {
 		for (i = 0; i < RK616_CODEC_PLAYBACK_POWER_UP_LIST_LEN; i++) {
 			snd_soc_write(codec, playback_power_up_list[i].reg,
 				playback_power_up_list[i].value);
@@ -739,14 +743,18 @@ static int rk616_codec_power_up(int type)
 				capture_power_up_list[i].value);
 		}
 	} else if (type == RK616_CODEC_INCALL) {
+		//delay for MOS or AMP mute, or it will get some pop noise.
+		mdelay(SPK_AMP_DELAY);
+
 		snd_soc_update_bits(codec, RK616_PGA_AGC_CTL,
 			0x0f, 0x09); //set for capture pop noise
 		snd_soc_update_bits(codec, RK616_MIXINL_CTL,
-			RK616_MIL_F_IN3L | RK616_MIL_MUTE, 0); //IN3L to MIXINL, unmute IN3L
+			RK616_MIL_F_IN3L | RK616_MIL_MUTE | RK616_MIL_PWRD,
+			0); //IN3L to MIXINL, unmute IN3L
 		snd_soc_update_bits(codec, RK616_MIXINL_VOL2,
-			RK616_MIL_F_IN3L_VOL_MASK, 7); //IN3L to MIXINL vol
+			RK616_MIL_F_IN3L_VOL_MASK, 0); //IN3L to MIXINL vol
 		snd_soc_update_bits(codec, RK616_PGAL_CTL,
-			0xff, 0x9f); //PU unmute PGAL,PGAL vol
+			0xff, 15); //PU unmute PGAL,PGAL vol
 		snd_soc_update_bits(codec, RK616_HPMIX_CTL,
 			RK616_HML_F_PGAL | RK616_HMR_F_PGAL, 0);
 	}
@@ -773,6 +781,7 @@ static int rk616_codec_power_down(int type)
 
 	// mute output for pop noise
 	if (type == RK616_CODEC_PLAYBACK ||
+		type == RK616_CODEC_INCALL ||
 		type == RK616_CODEC_ALL) {
 		rk616_set_gpio(RK616_CODEC_SET_SPK, GPIO_LOW);
 		rk616_set_gpio(RK616_CODEC_SET_HP, GPIO_LOW);
@@ -793,6 +802,9 @@ static int rk616_codec_power_down(int type)
 	}
 
 	if (type == RK616_CODEC_INCALL || type == RK616_CODEC_ALL) {
+		//delay for MOS or AMP mute, or it will get some pop noise.
+		mdelay(SPK_AMP_DELAY);
+
 		//close incall route
 		snd_soc_update_bits(codec, RK616_HPMIX_CTL,
 			RK616_HML_F_PGAL | RK616_HMR_F_PGAL,
@@ -800,10 +812,10 @@ static int rk616_codec_power_down(int type)
 		snd_soc_update_bits(codec, RK616_PGA_AGC_CTL,
 			0x0f, 0x0c);
 		snd_soc_update_bits(codec, RK616_MIXINL_CTL,
-			RK616_MIL_F_IN3L | RK616_MIL_MUTE,
-			RK616_MIL_F_IN3L | RK616_MIL_MUTE);
+			RK616_MIL_F_IN3L | RK616_MIL_MUTE | RK616_MIL_PWRD,
+			RK616_MIL_F_IN3L | RK616_MIL_MUTE | RK616_MIL_PWRD);
 		snd_soc_update_bits(codec, RK616_MIXINL_VOL2,
-			RK616_MIL_F_IN3L_VOL_MASK, 4);
+			RK616_MIL_F_IN3L_VOL_MASK, 0);
 		snd_soc_update_bits(codec, RK616_PGAL_CTL,
 			0xff, 0xcc);
 	}
@@ -1105,12 +1117,17 @@ static const char *rk616_capture_path_mode[] = {"MIC OFF", "Main Mic", "Hands Fr
 
 static const char *rk616_voice_call_path_mode[] = {"OFF", "RCV", "SPK", "HP", "HP_NO_MIC", "BT"};//0-5
 
+static const char *rk616_modem_input_sel[] = {"ON", "OFF"};
+
 static const SOC_ENUM_SINGLE_DECL(rk616_playback_path_type, 0, 0, rk616_playback_path_mode);
 
 static const SOC_ENUM_SINGLE_DECL(rk616_capture_path_type, 0, 0, rk616_capture_path_mode);
 
 static const SOC_ENUM_SINGLE_DECL(rk616_voice_call_path_type, 0, 0, rk616_voice_call_path_mode);
 
+static const struct soc_enum rk616_modem_input_enum =
+	SOC_ENUM_SINGLE(RK616_PGAL_CTL, RK616_PGA_MUTE_SFT, 2, rk616_modem_input_sel);
+
 static int rk616_playback_path_get(struct snd_kcontrol *kcontrol,
 		struct snd_ctl_elem_value *ucontrol)
 {
@@ -1163,6 +1180,8 @@ static int rk616_playback_path_put(struct snd_kcontrol *kcontrol,
 		break;
 	case SPK_PATH:
 	case RING_SPK:
+		rk616_set_gpio(RK616_CODEC_SET_HP, GPIO_LOW);
+
 		if (pre_path == OFF)
 			rk616_codec_power_up(RK616_CODEC_PLAYBACK);
 
@@ -1177,6 +1196,8 @@ static int rk616_playback_path_put(struct snd_kcontrol *kcontrol,
 	case HP_NO_MIC:
 	case RING_HP:
 	case RING_HP_NO_MIC:
+		rk616_set_gpio(RK616_CODEC_SET_SPK, GPIO_LOW);
+
 		if (pre_path == OFF)
 			rk616_codec_power_up(RK616_CODEC_PLAYBACK);
 
@@ -1318,17 +1339,7 @@ static int rk616_voice_call_path_put(struct snd_kcontrol *kcontrol,
 		rk616->voice_call_path, pre_path);
 
 	//open playback route for incall route and keytone
-	if (pre_path == OFF) {
-		if (rk616->playback_path != OFF) {
-			//mute output for incall route pop nosie
-			rk616_set_gpio(RK616_CODEC_SET_SPK, GPIO_LOW);
-			rk616_set_gpio(RK616_CODEC_SET_HP, GPIO_LOW);
-			if (rk616->voice_call_path == SPK_PATH)
-				mdelay(SPK_AMP_DELAY);
-			else if (rk616->voice_call_path == HP_PATH ||
-				rk616->voice_call_path == HP_NO_MIC)
-				mdelay(HP_MOS_DELAY);
-		} else
+	if (pre_path == OFF && rk616->playback_path == OFF) {
 			rk616_codec_power_up(RK616_CODEC_PLAYBACK);
 	}
 
@@ -1336,15 +1347,6 @@ static int rk616_voice_call_path_put(struct snd_kcontrol *kcontrol,
 	case OFF:
 		if (pre_path != RCV &&
 			pre_path != BT) {
-			//mute output for incall route pop nosie
-			rk616_set_gpio(RK616_CODEC_SET_SPK, GPIO_LOW);
-			rk616_set_gpio(RK616_CODEC_SET_HP, GPIO_LOW);
-			if (pre_path == SPK_PATH)
-				mdelay(SPK_AMP_DELAY);
-			else if (pre_path == HP_PATH ||
-				pre_path == HP_NO_MIC)
-				mdelay(HP_MOS_DELAY);
-
 			rk616_codec_power_down(RK616_CODEC_INCALL);
 		}
 
@@ -1361,15 +1363,6 @@ static int rk616_voice_call_path_put(struct snd_kcontrol *kcontrol,
 		//rcv is controled by modem, so close incall route
 		if (pre_path != OFF &&
 			pre_path != BT) {
-			//mute output for incall route pop nosie
-			rk616_set_gpio(RK616_CODEC_SET_SPK, GPIO_LOW);
-			rk616_set_gpio(RK616_CODEC_SET_HP, GPIO_LOW);
-			if (pre_path == SPK_PATH)
-				mdelay(SPK_AMP_DELAY);
-			else if (pre_path == HP_PATH ||
-				pre_path == HP_NO_MIC)
-				mdelay(HP_MOS_DELAY);
-
 			rk616_codec_power_down(RK616_CODEC_INCALL);
 		}
 
@@ -1437,15 +1430,6 @@ static int rk616_voice_call_path_put(struct snd_kcontrol *kcontrol,
 		//BT is controled by modem, so close incall route
 		if (pre_path != OFF &&
 			pre_path != RCV) {
-			//mute output for incall route pop nosie
-			rk616_set_gpio(RK616_CODEC_SET_SPK, GPIO_LOW);
-			rk616_set_gpio(RK616_CODEC_SET_HP, GPIO_LOW);
-
-			if (rk616->voice_call_path == SPK_PATH)
-				mdelay(SPK_AMP_DELAY);
-			else if (rk616->voice_call_path == HP_PATH ||
-				rk616->voice_call_path == HP_NO_MIC)
-				mdelay(HP_MOS_DELAY);
 			rk616_codec_power_down(RK616_CODEC_INCALL);
 		}
 
@@ -1468,6 +1452,13 @@ static const struct snd_kcontrol_new rk616_snd_path_controls[] = {
 
 	SOC_ENUM_EXT("Voice Call Path", rk616_voice_call_path_type,
 		rk616_voice_call_path_get, rk616_voice_call_path_put),
+
+	/*
+	* When modem connecting, it will make some pop noise.
+	* So, add this control for modem. Modem will set 'OFF'
+	* before incall connected, and set 'ON' after connected.
+	*/
+	SOC_ENUM("Modem Input Enable",  rk616_modem_input_enum),
 };
 
 static int rk616_dacl_event(struct snd_soc_dapm_widget *w,
-- 
2.34.1