summary refs log tree commit diff
path: root/sound
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2011-10-14 15:26:20 +0200
committerTakashi Iwai <tiwai@suse.de>2011-10-27 16:58:11 +0200
commit6b45214277bec2193ad3ccb8d7aa6100b5a0f1a9 (patch)
treeede0051a5028349463d608ed7c514000bc049bb4 /sound
parent254f296840b64b034a4c850d45dbde7c040f0819 (diff)
downloadlinux-6b45214277bec2193ad3ccb8d7aa6100b5a0f1a9.tar.gz
ALSA: hda - Fix ADC input-amp handling for Cx20549 codec
It seems that Conexant CX20549 chip handle only a single input-amp even
though the audio-input widget has multiple sources.  This has been never
clear, and I implemented in the current way based on the debug information
I got at the early time -- the device reacts individual input-amp values
for different sources.  This is true for another Conexant codec, but it's
not applied to CX20549 actually.

This patch changes the auto-parser code to handle a single input-amp
per audio-in widget for CX20549.  After applying this, you'll see only a
single "Capture" volume control instead of separate "Mic" or "Line"
captures when the device is set up to use a single ADC.

We haven't tested 20551 and 20561 codecs yet.  If these show the similar
behavior like 20549, they need to set spec->single_adc_amp=1, too.

Cc: <stable@kernel.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r--sound/pci/hda/patch_conexant.c29
1 files changed, 27 insertions, 2 deletions
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 1d69a3e0ce2c..0c8b5a1993ed 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -137,6 +137,7 @@ struct conexant_spec {
 	unsigned int hp_laptop:1;
 	unsigned int asus:1;
 	unsigned int pin_eapd_ctrls:1;
+	unsigned int single_adc_amp:1;
 
 	unsigned int adc_switching:1;
 
@@ -4213,6 +4214,8 @@ static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid,
 		int idx = get_input_connection(codec, adc_nid, nid);
 		if (idx < 0)
 			continue;
+		if (spec->single_adc_amp)
+			idx = 0;
 		return cx_auto_add_volume_idx(codec, label, pfx,
 					      cidx, adc_nid, HDA_INPUT, idx);
 	}
@@ -4253,14 +4256,21 @@ static int cx_auto_build_input_controls(struct hda_codec *codec)
 	struct hda_input_mux *imux = &spec->private_imux;
 	const char *prev_label;
 	int input_conn[HDA_MAX_NUM_INPUTS];
-	int i, err, cidx;
+	int i, j, err, cidx;
 	int multi_connection;
 
+	if (!imux->num_items)
+		return 0;
+
 	multi_connection = 0;
 	for (i = 0; i < imux->num_items; i++) {
 		cidx = get_input_connection(codec, spec->imux_info[i].adc,
 					    spec->imux_info[i].pin);
-		input_conn[i] = (spec->imux_info[i].adc << 8) | cidx;
+		if (cidx < 0)
+			continue;
+		input_conn[i] = spec->imux_info[i].adc;
+		if (!spec->single_adc_amp)
+			input_conn[i] |= cidx << 8;
 		if (i > 0 && input_conn[i] != input_conn[0])
 			multi_connection = 1;
 	}
@@ -4289,6 +4299,15 @@ static int cx_auto_build_input_controls(struct hda_codec *codec)
 			err = cx_auto_add_capture_volume(codec, nid,
 							 "Capture", "", cidx);
 		} else {
+			bool dup_found = false;
+			for (j = 0; j < i; j++) {
+				if (input_conn[j] == input_conn[i]) {
+					dup_found = true;
+					break;
+				}
+			}
+			if (dup_found)
+				continue;
 			err = cx_auto_add_capture_volume(codec, nid,
 							 label, " Capture", cidx);
 		}
@@ -4413,6 +4432,12 @@ static int patch_conexant_auto(struct hda_codec *codec)
 	codec->spec = spec;
 	codec->pin_amp_workaround = 1;
 
+	switch (codec->vendor_id) {
+	case 0x14f15045:
+		spec->single_adc_amp = 1;
+		break;
+	}
+
 	apply_pin_fixup(codec, cxt_fixups, cxt_pincfg_tbl);
 
 	err = cx_auto_search_adcs(codec);