From d170db12ac67809c4f43e3f548b5564e020a5282 Mon Sep 17 00:00:00 2001
From: Shrirang Bagul <shrirang_bagul@asus.com>
Date: Mon, 25 Apr 2011 11:15:40 +0800
Subject: [PATCH] 2-mic capture for x86-Eeebot

---
 sound/pci/hda/patch_realtek.c |  159 +++++++++++++++++++++++++++++++++++++---
 1 files changed, 147 insertions(+), 12 deletions(-)

diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index dff209f..d14fe36 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -14152,19 +14152,33 @@ static hda_nid_t alc269_capsrc_nids[1] = {
 	0x23,
 };
 
-static hda_nid_t alc269vb_adc_nids[1] = {
-	/* ADC1 */
-	0x09,
+static hda_nid_t alc269vb_adc_nids[2] = {
+	/* ADC1-2 */
+	0x09, 0x08,
 };
 
 static hda_nid_t alc269vb_capsrc_nids[1] = {
-	0x22,
+	0x22, 0x23,
 };
 
 static hda_nid_t alc269_adc_candidates[] = {
 	0x08, 0x09, 0x07,
 };
 
+static struct hda_channel_mode alc269_4ch_modes[1] = {
+	{ 4, NULL},
+};
+
+static struct hda_input_mux alc269vb_capture_sources[2] = {
+	{
+		.num_items = 2,
+		.items = {
+			{"Mic-1", 0x0},
+			{"Mic-2", 0x2},
+		},
+	},
+};
+
 #define alc269_modes		alc260_modes
 #define alc269_capture_source	alc880_lg_lw_capture_source
 
@@ -14275,6 +14289,16 @@ static struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = {
 	{ } /* end */
 };
 
+static struct snd_kcontrol_new alc269vb_test_laptop_analog_capture_mixer[] = {
+	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME_IDX("Capture 2 Volume", 0x1, 0x9, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE_IDX("Capture 2 Switch", 0x1, 0x09, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic-1 Boost Volume", 0x18, 0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic-2 Boost Volume", 0x19, 0, HDA_INPUT),
+	{ } /* end */
+};
+
 static struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
@@ -14463,10 +14487,10 @@ static struct hda_verb alc269vb_laptop_dmic_init_verbs[] = {
 static struct hda_verb alc269vb_laptop_amic_init_verbs[] = {
 	{0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
 	{0x22, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
 	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
-	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
+	//{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
 	{0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
 	{}
 };
@@ -14567,7 +14591,7 @@ static void alc269vb_laptop_dmic_setup(struct hda_codec *codec)
 static void alc269_laptop_inithook(struct hda_codec *codec)
 {
 	alc269_speaker_automute(codec);
-	alc_mic_automute(codec);
+	//alc_mic_automute(codec);
 }
 
 /*
@@ -15115,14 +15139,17 @@ static struct alc_config_preset alc269_presets[] = {
 	},
 	[ALC269VB_AMIC] = {
 		.mixers = { alc269vb_laptop_mixer },
-		.cap_mixer = alc269vb_laptop_analog_capture_mixer,
+		.cap_mixer = alc269vb_test_laptop_analog_capture_mixer,
 		.init_verbs = { alc269vb_init_verbs,
 				alc269vb_laptop_amic_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc269_dac_nids),
 		.dac_nids = alc269_dac_nids,
 		.hp_nid = 0x03,
-		.num_channel_mode = ARRAY_SIZE(alc269_modes),
-		.channel_mode = alc269_modes,
+		.num_channel_mode = ARRAY_SIZE(alc269_4ch_modes),
+		.channel_mode = alc269_4ch_modes,
+		.num_mux_defs =
+			ARRAY_SIZE(alc269vb_capture_sources),
+		.input_mux = alc269vb_capture_sources,
 		.unsol_event = alc269_laptop_unsol_event,
 		.setup = alc269vb_laptop_amic_setup,
 		.init_hook = alc269_laptop_inithook,
@@ -15221,6 +15248,76 @@ static int alc269_fill_coef(struct hda_codec *codec)
 	return 0;
 }
 
+static int alc269_capture_4ch_pcm_prepare(struct hda_pcm_stream *hinfo,
+					struct hda_codec *codec,
+					unsigned int stream_tag,
+					unsigned int format,
+					struct snd_pcm_substream *substream)
+{
+	struct alc_spec *spec = codec->spec;
+
+	snd_hda_codec_setup_stream(codec, 0x08, stream_tag, 0, format);
+
+	return 0;
+}
+
+static int alc269_capture_4ch_pcm_cleanup(struct hda_pcm_stream *hinfo,
+					struct hda_codec *codec,
+					struct snd_pcm_substream *substream)
+{
+	snd_hda_codec_cleanup_stream(codec, 0x08);
+
+	return 0;
+}
+
+static int alc269_capture_4ch_alt_pcm_prepare(struct hda_pcm_stream *hinfo,
+					struct hda_codec *codec,
+					unsigned int stream_tag,
+					unsigned int format,
+					struct snd_pcm_substream *substream)
+{
+	struct alc_spec *spec = codec->spec;
+
+	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
+				   stream_tag, 0, format);
+
+	return 0;
+}
+
+static int alc269_capture_4ch_alt_pcm_cleanup(struct hda_pcm_stream *hinfo,
+					struct hda_codec *codec,
+					struct snd_pcm_substream *substream)
+{
+	struct alc_spec *spec = codec->spec;
+
+	snd_hda_codec_cleanup_stream(codec,
+				     spec->adc_nids[substream->number +1]);
+
+	return 0;
+}
+
+static struct hda_pcm_stream alc269_pcm_analog_4ch_capture = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+	/* NID is set in alc_build_pcms */
+	/*.ops = {
+		.prepare = alc269_capture_4ch_pcm_prepare,
+		.cleanup = alc269_capture_4ch_pcm_cleanup
+	},*/
+};
+
+static struct hda_pcm_stream alc269_pcm_analog_alt_4ch_capture = {
+	.substreams = 2,
+	.channels_min = 2,
+	.channels_max = 2,
+	/* NID is set in alc_build_pcms */
+	.ops = {
+		.prepare = alc269_capture_4ch_alt_pcm_prepare,
+		.cleanup = alc269_capture_4ch_alt_pcm_cleanup
+	},
+};
+
 static int patch_alc269(struct hda_codec *codec)
 {
 	struct alc_spec *spec;
@@ -15311,11 +15408,14 @@ static int patch_alc269(struct hda_codec *codec)
 		spec->stream_analog_capture = &dualmic_pcm_analog_capture;
 	} else {
 		spec->stream_analog_playback = &alc269_pcm_analog_playback;
-		spec->stream_analog_capture = &alc269_pcm_analog_capture;
+		//spec->stream_analog_capture = &alc269_pcm_analog_capture;
+		spec->stream_analog_capture = &alc269_pcm_analog_4ch_capture;
+		spec->stream_analog_alt_capture = &alc269_pcm_analog_alt_4ch_capture;
 	}
 	spec->stream_digital_playback = &alc269_pcm_digital_playback;
 	spec->stream_digital_capture = &alc269_pcm_digital_capture;
 
+#if 1
 	if (!spec->adc_nids) { /* wasn't filled automatically? use default */
 		if (spec->codec_variant == ALC269_TYPE_NORMAL) {
 			spec->adc_nids = alc269_adc_nids;
@@ -15327,7 +15427,42 @@ static int patch_alc269(struct hda_codec *codec)
 			spec->capsrc_nids = alc269vb_capsrc_nids;
 		}
 	}
-
+#else
+	// Shrirang
+	if (!spec->adc_nids && spec->input_mux) {
+		int i, j;
+		spec->num_adc_nids = 0;
+		for (i = 0; i < ARRAY_SIZE(alc269vb_adc_nids); i++) {
+			snd_printd("Config ADC# %d  \n", i);
+			const struct hda_input_mux *imux = spec->input_mux;
+			hda_nid_t cap;
+			hda_nid_t items[16];
+			hda_nid_t nid = alc269vb_adc_nids[i];
+			unsigned int wcap = get_wcaps(codec, nid);
+			/* get type */
+			wcap = get_wcaps_type(wcap);
+			if (wcap != AC_WID_AUD_IN)
+				continue;
+			spec->private_adc_nids[spec->num_adc_nids] = nid;
+			err = snd_hda_get_connections(codec, nid, &cap, 1);
+			if (err < 0)
+				continue;
+			err = snd_hda_get_connections(codec, cap, items,
+						      ARRAY_SIZE(items));
+			if (err < 0)
+				continue;
+			for (j = 0; j < imux->num_items; j++)
+				if (imux->items[j].index >= err)
+					break;
+			if (j < imux->num_items)
+				continue;
+			spec->private_capsrc_nids[spec->num_adc_nids] = cap;
+			spec->num_adc_nids++;
+		}
+		spec->adc_nids = spec->private_adc_nids;
+		spec->capsrc_nids = spec->private_capsrc_nids;
+	}
+#endif
 	if (!spec->cap_mixer)
 		set_capture_mixer(codec);
 	if (has_cdefine_beep(codec))
-- 
1.7.1

