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 { | |||
136 | unsigned int thinkpad:1; | 136 | unsigned int thinkpad:1; |
137 | unsigned int hp_laptop:1; | 137 | unsigned int hp_laptop:1; |
138 | unsigned int asus:1; | 138 | unsigned int asus:1; |
139 | unsigned int pin_eapd_ctrls:1; | ||
140 | unsigned int single_adc_amp:1; | ||
139 | 141 | ||
140 | unsigned int adc_switching:1; | 142 | unsigned int adc_switching:1; |
141 | 143 | ||
@@ -3430,12 +3432,14 @@ static void cx_auto_turn_eapd(struct hda_codec *codec, int num_pins, | |||
3430 | static void do_automute(struct hda_codec *codec, int num_pins, | 3432 | static void do_automute(struct hda_codec *codec, int num_pins, |
3431 | hda_nid_t *pins, bool on) | 3433 | hda_nid_t *pins, bool on) |
3432 | { | 3434 | { |
3435 | struct conexant_spec *spec = codec->spec; | ||
3433 | int i; | 3436 | int i; |
3434 | for (i = 0; i < num_pins; i++) | 3437 | for (i = 0; i < num_pins; i++) |
3435 | snd_hda_codec_write(codec, pins[i], 0, | 3438 | snd_hda_codec_write(codec, pins[i], 0, |
3436 | AC_VERB_SET_PIN_WIDGET_CONTROL, | 3439 | AC_VERB_SET_PIN_WIDGET_CONTROL, |
3437 | on ? PIN_OUT : 0); | 3440 | on ? PIN_OUT : 0); |
3438 | cx_auto_turn_eapd(codec, num_pins, pins, on); | 3441 | if (spec->pin_eapd_ctrls) |
3442 | cx_auto_turn_eapd(codec, num_pins, pins, on); | ||
3439 | } | 3443 | } |
3440 | 3444 | ||
3441 | static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) | 3445 | 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) | |||
3460 | int on = 1; | 3464 | int on = 1; |
3461 | 3465 | ||
3462 | /* turn on HP EAPD when HP jacks are present */ | 3466 | /* turn on HP EAPD when HP jacks are present */ |
3463 | if (spec->auto_mute) | 3467 | if (spec->pin_eapd_ctrls) { |
3464 | on = spec->hp_present; | 3468 | if (spec->auto_mute) |
3465 | cx_auto_turn_eapd(codec, cfg->hp_outs, cfg->hp_pins, on); | 3469 | on = spec->hp_present; |
3470 | cx_auto_turn_eapd(codec, cfg->hp_outs, cfg->hp_pins, on); | ||
3471 | } | ||
3472 | |||
3466 | /* mute speakers in auto-mode if HP or LO jacks are plugged */ | 3473 | /* mute speakers in auto-mode if HP or LO jacks are plugged */ |
3467 | if (spec->auto_mute) | 3474 | if (spec->auto_mute) |
3468 | on = !(spec->hp_present || | 3475 | on = !(spec->hp_present || |
@@ -3889,20 +3896,10 @@ static void cx_auto_parse_beep(struct hda_codec *codec) | |||
3889 | #define cx_auto_parse_beep(codec) | 3896 | #define cx_auto_parse_beep(codec) |
3890 | #endif | 3897 | #endif |
3891 | 3898 | ||
3892 | static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) | 3899 | /* parse EAPDs */ |
3893 | { | ||
3894 | int i; | ||
3895 | for (i = 0; i < nums; i++) | ||
3896 | if (list[i] == nid) | ||
3897 | return true; | ||
3898 | return false; | ||
3899 | } | ||
3900 | |||
3901 | /* parse extra-EAPD that aren't assigned to any pins */ | ||
3902 | static void cx_auto_parse_eapd(struct hda_codec *codec) | 3900 | static void cx_auto_parse_eapd(struct hda_codec *codec) |
3903 | { | 3901 | { |
3904 | struct conexant_spec *spec = codec->spec; | 3902 | struct conexant_spec *spec = codec->spec; |
3905 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
3906 | hda_nid_t nid, end_nid; | 3903 | hda_nid_t nid, end_nid; |
3907 | 3904 | ||
3908 | end_nid = codec->start_nid + codec->num_nodes; | 3905 | end_nid = codec->start_nid + codec->num_nodes; |
@@ -3911,14 +3908,18 @@ static void cx_auto_parse_eapd(struct hda_codec *codec) | |||
3911 | continue; | 3908 | continue; |
3912 | if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)) | 3909 | if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)) |
3913 | continue; | 3910 | continue; |
3914 | if (found_in_nid_list(nid, cfg->line_out_pins, cfg->line_outs) || | ||
3915 | found_in_nid_list(nid, cfg->hp_pins, cfg->hp_outs) || | ||
3916 | found_in_nid_list(nid, cfg->speaker_pins, cfg->speaker_outs)) | ||
3917 | continue; | ||
3918 | spec->eapds[spec->num_eapds++] = nid; | 3911 | spec->eapds[spec->num_eapds++] = nid; |
3919 | if (spec->num_eapds >= ARRAY_SIZE(spec->eapds)) | 3912 | if (spec->num_eapds >= ARRAY_SIZE(spec->eapds)) |
3920 | break; | 3913 | break; |
3921 | } | 3914 | } |
3915 | |||
3916 | /* NOTE: below is a wild guess; if we have more than two EAPDs, | ||
3917 | * it's a new chip, where EAPDs are supposed to be associated to | ||
3918 | * pins, and we can control EAPD per pin. | ||
3919 | * OTOH, if only one or two EAPDs are found, it's an old chip, | ||
3920 | * thus it might control over all pins. | ||
3921 | */ | ||
3922 | spec->pin_eapd_ctrls = spec->num_eapds > 2; | ||
3922 | } | 3923 | } |
3923 | 3924 | ||
3924 | static int cx_auto_parse_auto_config(struct hda_codec *codec) | 3925 | 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) | |||
4024 | } | 4025 | } |
4025 | } | 4026 | } |
4026 | cx_auto_update_speakers(codec); | 4027 | cx_auto_update_speakers(codec); |
4027 | /* turn on/off extra EAPDs, too */ | 4028 | /* turn on all EAPDs if no individual EAPD control is available */ |
4028 | cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true); | 4029 | if (!spec->pin_eapd_ctrls) |
4030 | cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true); | ||
4029 | } | 4031 | } |
4030 | 4032 | ||
4031 | static void cx_auto_init_input(struct hda_codec *codec) | 4033 | 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, | |||
4212 | int idx = get_input_connection(codec, adc_nid, nid); | 4214 | int idx = get_input_connection(codec, adc_nid, nid); |
4213 | if (idx < 0) | 4215 | if (idx < 0) |
4214 | continue; | 4216 | continue; |
4217 | if (spec->single_adc_amp) | ||
4218 | idx = 0; | ||
4215 | return cx_auto_add_volume_idx(codec, label, pfx, | 4219 | return cx_auto_add_volume_idx(codec, label, pfx, |
4216 | cidx, adc_nid, HDA_INPUT, idx); | 4220 | cidx, adc_nid, HDA_INPUT, idx); |
4217 | } | 4221 | } |
@@ -4252,14 +4256,21 @@ static int cx_auto_build_input_controls(struct hda_codec *codec) | |||
4252 | struct hda_input_mux *imux = &spec->private_imux; | 4256 | struct hda_input_mux *imux = &spec->private_imux; |
4253 | const char *prev_label; | 4257 | const char *prev_label; |
4254 | int input_conn[HDA_MAX_NUM_INPUTS]; | 4258 | int input_conn[HDA_MAX_NUM_INPUTS]; |
4255 | int i, err, cidx; | 4259 | int i, j, err, cidx; |
4256 | int multi_connection; | 4260 | int multi_connection; |
4257 | 4261 | ||
4262 | if (!imux->num_items) | ||
4263 | return 0; | ||
4264 | |||
4258 | multi_connection = 0; | 4265 | multi_connection = 0; |
4259 | for (i = 0; i < imux->num_items; i++) { | 4266 | for (i = 0; i < imux->num_items; i++) { |
4260 | cidx = get_input_connection(codec, spec->imux_info[i].adc, | 4267 | cidx = get_input_connection(codec, spec->imux_info[i].adc, |
4261 | spec->imux_info[i].pin); | 4268 | spec->imux_info[i].pin); |
4262 | input_conn[i] = (spec->imux_info[i].adc << 8) | cidx; | 4269 | if (cidx < 0) |
4270 | continue; | ||
4271 | input_conn[i] = spec->imux_info[i].adc; | ||
4272 | if (!spec->single_adc_amp) | ||
4273 | input_conn[i] |= cidx << 8; | ||
4263 | if (i > 0 && input_conn[i] != input_conn[0]) | 4274 | if (i > 0 && input_conn[i] != input_conn[0]) |
4264 | multi_connection = 1; | 4275 | multi_connection = 1; |
4265 | } | 4276 | } |
@@ -4288,6 +4299,15 @@ static int cx_auto_build_input_controls(struct hda_codec *codec) | |||
4288 | err = cx_auto_add_capture_volume(codec, nid, | 4299 | err = cx_auto_add_capture_volume(codec, nid, |
4289 | "Capture", "", cidx); | 4300 | "Capture", "", cidx); |
4290 | } else { | 4301 | } else { |
4302 | bool dup_found = false; | ||
4303 | for (j = 0; j < i; j++) { | ||
4304 | if (input_conn[j] == input_conn[i]) { | ||
4305 | dup_found = true; | ||
4306 | break; | ||
4307 | } | ||
4308 | } | ||
4309 | if (dup_found) | ||
4310 | continue; | ||
4291 | err = cx_auto_add_capture_volume(codec, nid, | 4311 | err = cx_auto_add_capture_volume(codec, nid, |
4292 | label, " Capture", cidx); | 4312 | label, " Capture", cidx); |
4293 | } | 4313 | } |
@@ -4412,6 +4432,12 @@ static int patch_conexant_auto(struct hda_codec *codec) | |||
4412 | codec->spec = spec; | 4432 | codec->spec = spec; |
4413 | codec->pin_amp_workaround = 1; | 4433 | codec->pin_amp_workaround = 1; |
4414 | 4434 | ||
4435 | switch (codec->vendor_id) { | ||
4436 | case 0x14f15045: | ||
4437 | spec->single_adc_amp = 1; | ||
4438 | break; | ||
4439 | } | ||
4440 | |||
4415 | apply_pin_fixup(codec, cxt_fixups, cxt_pincfg_tbl); | 4441 | apply_pin_fixup(codec, cxt_fixups, cxt_pincfg_tbl); |
4416 | 4442 | ||
4417 | err = cx_auto_search_adcs(codec); | 4443 | err = cx_auto_search_adcs(codec); |