diff options
Diffstat (limited to 'sound/pci/hda/patch_conexant.c')
-rw-r--r-- | sound/pci/hda/patch_conexant.c | 72 |
1 files changed, 49 insertions, 23 deletions
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 686ec6d75c64..0c8b5a1993ed 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -136,6 +136,8 @@ struct conexant_spec { unsigned int thinkpad:1; 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; @@ -3430,12 +3432,14 @@ static void cx_auto_turn_eapd(struct hda_codec *codec, int num_pins, static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, bool on) { + struct conexant_spec *spec = codec->spec; int i; for (i = 0; i < num_pins; i++) snd_hda_codec_write(codec, pins[i], 0, AC_VERB_SET_PIN_WIDGET_CONTROL, on ? PIN_OUT : 0); - cx_auto_turn_eapd(codec, num_pins, pins, on); + if (spec->pin_eapd_ctrls) + cx_auto_turn_eapd(codec, num_pins, pins, on); } static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) @@ -3460,9 +3464,12 @@ static void cx_auto_update_speakers(struct hda_codec *codec) int on = 1; /* turn on HP EAPD when HP jacks are present */ - if (spec->auto_mute) - on = spec->hp_present; - cx_auto_turn_eapd(codec, cfg->hp_outs, cfg->hp_pins, on); + if (spec->pin_eapd_ctrls) { + if (spec->auto_mute) + on = spec->hp_present; + cx_auto_turn_eapd(codec, cfg->hp_outs, cfg->hp_pins, on); + } + /* mute speakers in auto-mode if HP or LO jacks are plugged */ if (spec->auto_mute) on = !(spec->hp_present || @@ -3889,20 +3896,10 @@ static void cx_auto_parse_beep(struct hda_codec *codec) #define cx_auto_parse_beep(codec) #endif -static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) -{ - int i; - for (i = 0; i < nums; i++) - if (list[i] == nid) - return true; - return false; -} - -/* parse extra-EAPD that aren't assigned to any pins */ +/* parse EAPDs */ static void cx_auto_parse_eapd(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; hda_nid_t nid, end_nid; end_nid = codec->start_nid + codec->num_nodes; @@ -3911,14 +3908,18 @@ static void cx_auto_parse_eapd(struct hda_codec *codec) continue; if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)) continue; - if (found_in_nid_list(nid, cfg->line_out_pins, cfg->line_outs) || - found_in_nid_list(nid, cfg->hp_pins, cfg->hp_outs) || - found_in_nid_list(nid, cfg->speaker_pins, cfg->speaker_outs)) - continue; spec->eapds[spec->num_eapds++] = nid; if (spec->num_eapds >= ARRAY_SIZE(spec->eapds)) break; } + + /* NOTE: below is a wild guess; if we have more than two EAPDs, + * it's a new chip, where EAPDs are supposed to be associated to + * pins, and we can control EAPD per pin. + * OTOH, if only one or two EAPDs are found, it's an old chip, + * thus it might control over all pins. + */ + spec->pin_eapd_ctrls = spec->num_eapds > 2; } static int cx_auto_parse_auto_config(struct hda_codec *codec) @@ -4024,8 +4025,9 @@ static void cx_auto_init_output(struct hda_codec *codec) } } cx_auto_update_speakers(codec); - /* turn on/off extra EAPDs, too */ - cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true); + /* turn on all EAPDs if no individual EAPD control is available */ + if (!spec->pin_eapd_ctrls) + cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true); } static void cx_auto_init_input(struct hda_codec *codec) @@ -4212,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); } @@ -4252,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; } @@ -4288,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); } @@ -4412,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); |