>From 0ed09f1e36d22b87712f1494513fe8ca7acee0ce Mon Sep 17 00:00:00 2001
From: Michael Frey (Senior Manager, MID) <michael.frey@canonical.com>
Date: Thu, 16 Jul 2009 11:09:17 -0400
Subject: [PATCH] UBUNTU: SAUCE: Fix for rear audio port (Conexant 5051 Codec)

BugLink: https://bugs.edge.launchpad.net/walpole-anakin/+bug/394960

Summary: No sound through the rear audio port.

Signed-off-by: Michael Frey (Senior Manager, MID) <michael.frey@canonical.com>
---
 sound/pci/hda/patch_conexant.c |   91 +++++++++++++++++++++++++++------------
 1 files changed, 63 insertions(+), 28 deletions(-)

diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 00ed53e..0136840 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -39,7 +39,6 @@
 #define CONEXANT_MIC_EVENT	0x38
 
 
-
 struct conexant_spec {
 
 	struct snd_kcontrol_new *mixers[5];
@@ -60,6 +59,9 @@ struct conexant_spec {
 	unsigned int hp_present;
 	unsigned int need_dac_fix;
 
+	unsigned int port_a_mode;
+	unsigned int port_d_mode;
+
 	/* capture */
 	unsigned int num_adc_nids;
 	hda_nid_t *adc_nids;
@@ -80,7 +82,7 @@ struct conexant_spec {
 	int num_channel_mode;
 
 	/* PCM information */
-	struct hda_pcm pcm_rec[2];	/* used in build_pcms() */
+	struct hda_pcm pcm_rec[3];	/* used in build_pcms() */
 
 	unsigned int spdif_route;
 
@@ -262,41 +264,50 @@ static int conexant_build_pcms(struct hda_codec *codec)
 	struct conexant_spec *spec = codec->spec;
 	struct hda_pcm *info = spec->pcm_rec;
 
-	codec->num_pcms = 1;
+	codec->num_pcms = 0;
 	codec->pcm_info = info;
+	if (codec->afg) {
+		info->name = "CONEXANT Analog";
+		info->stream[SNDRV_PCM_STREAM_PLAYBACK] = conexant_pcm_analog_playback;
+		info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
+                        spec->multiout.max_channels;
+		info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
+                        spec->multiout.dac_nids[0];
+		if ((codec->vendor_id == 0x14f15051) ||
+				((codec->vendor_id & ~0xf) == 0x14f15060) ||
+				((codec->vendor_id & ~0xf) == 0x14f15070) ||
+				((codec->vendor_id & ~0xf) == 0x14f150D0))
+			info->stream[SNDRV_PCM_STREAM_CAPTURE] =
+                                cx5051_pcm_analog_capture;
+		else
+			info->stream[SNDRV_PCM_STREAM_CAPTURE] =
+                                conexant_pcm_analog_capture;
+		info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids;
+		info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
 
-	info->name = "CONEXANT Analog";
-	info->stream[SNDRV_PCM_STREAM_PLAYBACK] = conexant_pcm_analog_playback;
-	info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
-		spec->multiout.max_channels;
-	info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
-		spec->multiout.dac_nids[0];
-	if (codec->vendor_id == 0x14f15051)
-		info->stream[SNDRV_PCM_STREAM_CAPTURE] =
-			cx5051_pcm_analog_capture;
-	else
-		info->stream[SNDRV_PCM_STREAM_CAPTURE] =
-			conexant_pcm_analog_capture;
-	info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids;
-	info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
-
-	if (spec->multiout.dig_out_nid) {
 		info++;
 		codec->num_pcms++;
-		info->name = "Conexant Digital";
+	}
+
+	if (spec->multiout.dig_out_nid) {
+		info->name = "Conexant Digital Audio";
 		info->pcm_type = HDA_PCM_TYPE_SPDIF;
 		info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
-			conexant_pcm_digital_playback;
+                        conexant_pcm_digital_playback;
 		info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
-			spec->multiout.dig_out_nid;
+                        spec->multiout.dig_out_nid;
 		if (spec->dig_in_nid) {
 			info->stream[SNDRV_PCM_STREAM_CAPTURE] =
-				conexant_pcm_digital_capture;
+                                conexant_pcm_digital_capture;
 			info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
-				spec->dig_in_nid;
+                                spec->dig_in_nid;
 		}
+
+		info++;
+		codec->num_pcms++;
 	}
 
+
 	return 0;
 }
 
@@ -609,7 +620,6 @@ static void cxt5045_hp_unsol_event(struct hda_codec *codec,
 	case CONEXANT_MIC_EVENT:
 		cxt5045_hp_automic(codec);
 		break;
-
 	}
 }
 
@@ -1554,6 +1564,18 @@ static void cxt5051_update_speaker(struct hda_codec *codec)
 	pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0;
 	snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
 			    pinctl);
+
+	// Port A (HP)
+	pinctl = ((spec->hp_present & 1) && spec->cur_eapd) ? PIN_HP : 0;
+	snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+			    pinctl);
+	// Port D (LO), overriden by Port A
+	if(pinctl)
+		pinctl = 0;
+	else
+		pinctl = ((spec->hp_present & 2) && spec->cur_eapd) ? PIN_HP : 0;
+	snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+			    pinctl);
 }
 
 /* turn on/off EAPD (+ mute HP) as a master switch */
@@ -1611,10 +1633,19 @@ static void cxt5051_hp_automute(struct hda_codec *codec)
 {
 	struct conexant_spec *spec = codec->spec;
 
-	spec->hp_present = snd_hda_codec_read(codec, 0x16, 0,
+	// Port A
+	spec->hp_present = !!(snd_hda_codec_read(codec, 0x16, 0,
 				     AC_VERB_GET_PIN_SENSE, 0) &
-		AC_PINSENSE_PRESENCE;
+		AC_PINSENSE_PRESENCE);
+
+	// Port D
+	spec->hp_present |= (!!(snd_hda_codec_read(codec, 0x19, 0,
+				     AC_VERB_GET_PIN_SENSE, 0) &
+		AC_PINSENSE_PRESENCE)) << 1;
+
+
 	cxt5051_update_speaker(codec);
+
 }
 
 /* unsolicited event for HP jack sensing */
@@ -1686,6 +1717,9 @@ static struct hda_verb cxt5051_init_verbs[] = {
 	/* HP, Amp  */
 	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
+	/* Port D: LO */
+	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x19, AC_VERB_SET_CONNECT_SEL, 0x00},
 	/* DAC1 */	
 	{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	/* Record selector: Int mic */
@@ -1699,7 +1733,8 @@ static struct hda_verb cxt5051_init_verbs[] = {
 	{0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT},
 	{0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT},
 	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTC_EVENT},
-	{ } /* end */
+	{0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT},
+        { } /* end */
 };
 
 static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = {
-- 
1.6.0.4

