| From 6b45214277bec2193ad3ccb8d7aa6100b5a0f1a9 Mon Sep 17 00:00:00 2001 |
| From: Takashi Iwai <tiwai@suse.de> |
| Date: Fri, 14 Oct 2011 15:26:20 +0200 |
| Subject: ALSA: hda - Fix ADC input-amp handling for Cx20549 codec |
| |
| From: Takashi Iwai <tiwai@suse.de> |
| |
| commit 6b45214277bec2193ad3ccb8d7aa6100b5a0f1a9 upstream. |
| |
| 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. |
| |
| Signed-off-by: Takashi Iwai <tiwai@suse.de> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| |
| --- |
| sound/pci/hda/patch_conexant.c | 30 ++++++++++++++++++++++++++++-- |
| 1 file changed, 28 insertions(+), 2 deletions(-) |
| |
| --- 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; |
| |
| @@ -4256,6 +4257,8 @@ static int cx_auto_add_capture_volume(st |
| 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); |
| } |
| @@ -4296,14 +4299,21 @@ static int cx_auto_build_input_controls( |
| 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; |
| } |
| @@ -4332,6 +4342,15 @@ static int cx_auto_build_input_controls( |
| 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); |
| } |
| @@ -4408,6 +4427,13 @@ static int patch_conexant_auto(struct hd |
| return -ENOMEM; |
| codec->spec = spec; |
| codec->pin_amp_workaround = 1; |
| + |
| + switch (codec->vendor_id) { |
| + case 0x14f15045: |
| + spec->single_adc_amp = 1; |
| + break; |
| + } |
| + |
| err = cx_auto_search_adcs(codec); |
| if (err < 0) |
| return err; |