diff options
Diffstat (limited to 'sound/pci/hda/patch_realtek.c')
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 178 |
1 files changed, 154 insertions, 24 deletions
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index a7592f5e97d..ca1a87a4812 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -333,6 +333,12 @@ struct alc_spec { | |||
333 | hda_nid_t *capsrc_nids; | 333 | hda_nid_t *capsrc_nids; |
334 | hda_nid_t dig_in_nid; /* digital-in NID; optional */ | 334 | hda_nid_t dig_in_nid; /* digital-in NID; optional */ |
335 | 335 | ||
336 | /* capture setup for dynamic dual-adc switch */ | ||
337 | unsigned int cur_adc_idx; | ||
338 | hda_nid_t cur_adc; | ||
339 | unsigned int cur_adc_stream_tag; | ||
340 | unsigned int cur_adc_format; | ||
341 | |||
336 | /* capture source */ | 342 | /* capture source */ |
337 | unsigned int num_mux_defs; | 343 | unsigned int num_mux_defs; |
338 | const struct hda_input_mux *input_mux; | 344 | const struct hda_input_mux *input_mux; |
@@ -374,6 +380,7 @@ struct alc_spec { | |||
374 | 380 | ||
375 | /* other flags */ | 381 | /* other flags */ |
376 | unsigned int no_analog :1; /* digital I/O only */ | 382 | unsigned int no_analog :1; /* digital I/O only */ |
383 | unsigned int dual_adc_switch:1; /* switch ADCs (for ALC275) */ | ||
377 | int init_amp; | 384 | int init_amp; |
378 | 385 | ||
379 | /* for virtual master */ | 386 | /* for virtual master */ |
@@ -1010,6 +1017,29 @@ static int get_connection_index(struct hda_codec *codec, hda_nid_t mux, | |||
1010 | return -1; | 1017 | return -1; |
1011 | } | 1018 | } |
1012 | 1019 | ||
1020 | /* switch the current ADC according to the jack state */ | ||
1021 | static void alc_dual_mic_adc_auto_switch(struct hda_codec *codec) | ||
1022 | { | ||
1023 | struct alc_spec *spec = codec->spec; | ||
1024 | unsigned int present; | ||
1025 | hda_nid_t new_adc; | ||
1026 | |||
1027 | present = snd_hda_jack_detect(codec, spec->ext_mic.pin); | ||
1028 | if (present) | ||
1029 | spec->cur_adc_idx = 1; | ||
1030 | else | ||
1031 | spec->cur_adc_idx = 0; | ||
1032 | new_adc = spec->adc_nids[spec->cur_adc_idx]; | ||
1033 | if (spec->cur_adc && spec->cur_adc != new_adc) { | ||
1034 | /* stream is running, let's swap the current ADC */ | ||
1035 | snd_hda_codec_cleanup_stream(codec, spec->cur_adc); | ||
1036 | spec->cur_adc = new_adc; | ||
1037 | snd_hda_codec_setup_stream(codec, new_adc, | ||
1038 | spec->cur_adc_stream_tag, 0, | ||
1039 | spec->cur_adc_format); | ||
1040 | } | ||
1041 | } | ||
1042 | |||
1013 | static void alc_mic_automute(struct hda_codec *codec) | 1043 | static void alc_mic_automute(struct hda_codec *codec) |
1014 | { | 1044 | { |
1015 | struct alc_spec *spec = codec->spec; | 1045 | struct alc_spec *spec = codec->spec; |
@@ -1024,6 +1054,11 @@ static void alc_mic_automute(struct hda_codec *codec) | |||
1024 | if (snd_BUG_ON(!spec->adc_nids)) | 1054 | if (snd_BUG_ON(!spec->adc_nids)) |
1025 | return; | 1055 | return; |
1026 | 1056 | ||
1057 | if (spec->dual_adc_switch) { | ||
1058 | alc_dual_mic_adc_auto_switch(codec); | ||
1059 | return; | ||
1060 | } | ||
1061 | |||
1027 | cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0]; | 1062 | cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0]; |
1028 | 1063 | ||
1029 | present = snd_hda_jack_detect(codec, spec->ext_mic.pin); | 1064 | present = snd_hda_jack_detect(codec, spec->ext_mic.pin); |
@@ -3614,6 +3649,41 @@ static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | |||
3614 | return 0; | 3649 | return 0; |
3615 | } | 3650 | } |
3616 | 3651 | ||
3652 | /* analog capture with dynamic dual-adc changes */ | ||
3653 | static int dualmic_capture_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
3654 | struct hda_codec *codec, | ||
3655 | unsigned int stream_tag, | ||
3656 | unsigned int format, | ||
3657 | struct snd_pcm_substream *substream) | ||
3658 | { | ||
3659 | struct alc_spec *spec = codec->spec; | ||
3660 | spec->cur_adc = spec->adc_nids[spec->cur_adc_idx]; | ||
3661 | spec->cur_adc_stream_tag = stream_tag; | ||
3662 | spec->cur_adc_format = format; | ||
3663 | snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); | ||
3664 | return 0; | ||
3665 | } | ||
3666 | |||
3667 | static int dualmic_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
3668 | struct hda_codec *codec, | ||
3669 | struct snd_pcm_substream *substream) | ||
3670 | { | ||
3671 | struct alc_spec *spec = codec->spec; | ||
3672 | snd_hda_codec_cleanup_stream(codec, spec->cur_adc); | ||
3673 | spec->cur_adc = 0; | ||
3674 | return 0; | ||
3675 | } | ||
3676 | |||
3677 | static struct hda_pcm_stream dualmic_pcm_analog_capture = { | ||
3678 | .substreams = 1, | ||
3679 | .channels_min = 2, | ||
3680 | .channels_max = 2, | ||
3681 | .nid = 0, /* fill later */ | ||
3682 | .ops = { | ||
3683 | .prepare = dualmic_capture_pcm_prepare, | ||
3684 | .cleanup = dualmic_capture_pcm_cleanup | ||
3685 | }, | ||
3686 | }; | ||
3617 | 3687 | ||
3618 | /* | 3688 | /* |
3619 | */ | 3689 | */ |
@@ -5052,24 +5122,12 @@ static void fixup_automic_adc(struct hda_codec *codec) | |||
5052 | spec->auto_mic = 0; /* disable auto-mic to be sure */ | 5122 | spec->auto_mic = 0; /* disable auto-mic to be sure */ |
5053 | } | 5123 | } |
5054 | 5124 | ||
5055 | /* choose the ADC/MUX containing the input pin and initialize the setup */ | 5125 | /* set the default connection to that pin */ |
5056 | static void fixup_single_adc(struct hda_codec *codec) | 5126 | static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin) |
5057 | { | 5127 | { |
5058 | struct alc_spec *spec = codec->spec; | 5128 | struct alc_spec *spec = codec->spec; |
5059 | hda_nid_t pin = 0; | ||
5060 | int i; | 5129 | int i; |
5061 | 5130 | ||
5062 | /* search for the input pin; there must be only one */ | ||
5063 | for (i = 0; i < AUTO_PIN_LAST; i++) { | ||
5064 | if (spec->autocfg.input_pins[i]) { | ||
5065 | pin = spec->autocfg.input_pins[i]; | ||
5066 | break; | ||
5067 | } | ||
5068 | } | ||
5069 | if (!pin) | ||
5070 | return; | ||
5071 | |||
5072 | /* set the default connection to that pin */ | ||
5073 | for (i = 0; i < spec->num_adc_nids; i++) { | 5131 | for (i = 0; i < spec->num_adc_nids; i++) { |
5074 | hda_nid_t cap = spec->capsrc_nids ? | 5132 | hda_nid_t cap = spec->capsrc_nids ? |
5075 | spec->capsrc_nids[i] : spec->adc_nids[i]; | 5133 | spec->capsrc_nids[i] : spec->adc_nids[i]; |
@@ -5078,11 +5136,6 @@ static void fixup_single_adc(struct hda_codec *codec) | |||
5078 | idx = get_connection_index(codec, cap, pin); | 5136 | idx = get_connection_index(codec, cap, pin); |
5079 | if (idx < 0) | 5137 | if (idx < 0) |
5080 | continue; | 5138 | continue; |
5081 | /* use only this ADC */ | ||
5082 | if (spec->capsrc_nids) | ||
5083 | spec->capsrc_nids += i; | ||
5084 | spec->adc_nids += i; | ||
5085 | spec->num_adc_nids = 1; | ||
5086 | /* select or unmute this route */ | 5139 | /* select or unmute this route */ |
5087 | if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) { | 5140 | if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) { |
5088 | snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx, | 5141 | snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx, |
@@ -5091,10 +5144,45 @@ static void fixup_single_adc(struct hda_codec *codec) | |||
5091 | snd_hda_codec_write_cache(codec, cap, 0, | 5144 | snd_hda_codec_write_cache(codec, cap, 0, |
5092 | AC_VERB_SET_CONNECT_SEL, idx); | 5145 | AC_VERB_SET_CONNECT_SEL, idx); |
5093 | } | 5146 | } |
5147 | return i; /* return the found index */ | ||
5148 | } | ||
5149 | return -1; /* not found */ | ||
5150 | } | ||
5151 | |||
5152 | /* choose the ADC/MUX containing the input pin and initialize the setup */ | ||
5153 | static void fixup_single_adc(struct hda_codec *codec) | ||
5154 | { | ||
5155 | struct alc_spec *spec = codec->spec; | ||
5156 | hda_nid_t pin = 0; | ||
5157 | int i; | ||
5158 | |||
5159 | /* search for the input pin; there must be only one */ | ||
5160 | for (i = 0; i < AUTO_PIN_LAST; i++) { | ||
5161 | if (spec->autocfg.input_pins[i]) { | ||
5162 | pin = spec->autocfg.input_pins[i]; | ||
5163 | break; | ||
5164 | } | ||
5165 | } | ||
5166 | if (!pin) | ||
5094 | return; | 5167 | return; |
5168 | i = init_capsrc_for_pin(codec, pin); | ||
5169 | if (i >= 0) { | ||
5170 | /* use only this ADC */ | ||
5171 | if (spec->capsrc_nids) | ||
5172 | spec->capsrc_nids += i; | ||
5173 | spec->adc_nids += i; | ||
5174 | spec->num_adc_nids = 1; | ||
5095 | } | 5175 | } |
5096 | } | 5176 | } |
5097 | 5177 | ||
5178 | /* initialize dual adcs */ | ||
5179 | static void fixup_dual_adc_switch(struct hda_codec *codec) | ||
5180 | { | ||
5181 | struct alc_spec *spec = codec->spec; | ||
5182 | init_capsrc_for_pin(codec, spec->ext_mic.pin); | ||
5183 | init_capsrc_for_pin(codec, spec->int_mic.pin); | ||
5184 | } | ||
5185 | |||
5098 | static void set_capture_mixer(struct hda_codec *codec) | 5186 | static void set_capture_mixer(struct hda_codec *codec) |
5099 | { | 5187 | { |
5100 | struct alc_spec *spec = codec->spec; | 5188 | struct alc_spec *spec = codec->spec; |
@@ -5108,7 +5196,10 @@ static void set_capture_mixer(struct hda_codec *codec) | |||
5108 | }; | 5196 | }; |
5109 | if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) { | 5197 | if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) { |
5110 | int mux = 0; | 5198 | int mux = 0; |
5111 | if (spec->auto_mic) | 5199 | int num_adcs = spec->num_adc_nids; |
5200 | if (spec->dual_adc_switch) | ||
5201 | fixup_dual_adc_switch(codec); | ||
5202 | else if (spec->auto_mic) | ||
5112 | fixup_automic_adc(codec); | 5203 | fixup_automic_adc(codec); |
5113 | else if (spec->input_mux) { | 5204 | else if (spec->input_mux) { |
5114 | if (spec->input_mux->num_items > 1) | 5205 | if (spec->input_mux->num_items > 1) |
@@ -5116,7 +5207,9 @@ static void set_capture_mixer(struct hda_codec *codec) | |||
5116 | else if (spec->input_mux->num_items == 1) | 5207 | else if (spec->input_mux->num_items == 1) |
5117 | fixup_single_adc(codec); | 5208 | fixup_single_adc(codec); |
5118 | } | 5209 | } |
5119 | spec->cap_mixer = caps[mux][spec->num_adc_nids - 1]; | 5210 | if (spec->dual_adc_switch) |
5211 | num_adcs = 1; | ||
5212 | spec->cap_mixer = caps[mux][num_adcs - 1]; | ||
5120 | } | 5213 | } |
5121 | } | 5214 | } |
5122 | 5215 | ||
@@ -14141,6 +14234,36 @@ static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid) | |||
14141 | } | 14234 | } |
14142 | #endif /* CONFIG_SND_HDA_POWER_SAVE */ | 14235 | #endif /* CONFIG_SND_HDA_POWER_SAVE */ |
14143 | 14236 | ||
14237 | static int alc275_setup_dual_adc(struct hda_codec *codec) | ||
14238 | { | ||
14239 | struct alc_spec *spec = codec->spec; | ||
14240 | |||
14241 | if (codec->vendor_id != 0x10ec0275 || !spec->auto_mic) | ||
14242 | return 0; | ||
14243 | if ((spec->ext_mic.pin >= 0x18 && spec->int_mic.pin <= 0x13) || | ||
14244 | (spec->ext_mic.pin <= 0x12 && spec->int_mic.pin >= 0x18)) { | ||
14245 | if (spec->ext_mic.pin <= 0x12) { | ||
14246 | spec->private_adc_nids[0] = 0x08; | ||
14247 | spec->private_adc_nids[1] = 0x11; | ||
14248 | spec->private_capsrc_nids[0] = 0x23; | ||
14249 | spec->private_capsrc_nids[1] = 0x22; | ||
14250 | } else { | ||
14251 | spec->private_adc_nids[0] = 0x11; | ||
14252 | spec->private_adc_nids[1] = 0x08; | ||
14253 | spec->private_capsrc_nids[0] = 0x22; | ||
14254 | spec->private_capsrc_nids[1] = 0x23; | ||
14255 | } | ||
14256 | spec->adc_nids = spec->private_adc_nids; | ||
14257 | spec->capsrc_nids = spec->private_capsrc_nids; | ||
14258 | spec->num_adc_nids = 2; | ||
14259 | spec->dual_adc_switch = 1; | ||
14260 | snd_printdd("realtek: enabling dual ADC switchg (%02x:%02x)\n", | ||
14261 | spec->adc_nids[0], spec->adc_nids[1]); | ||
14262 | return 1; | ||
14263 | } | ||
14264 | return 0; | ||
14265 | } | ||
14266 | |||
14144 | /* | 14267 | /* |
14145 | * BIOS auto configuration | 14268 | * BIOS auto configuration |
14146 | */ | 14269 | */ |
@@ -14180,11 +14303,14 @@ static int alc269_parse_auto_config(struct hda_codec *codec) | |||
14180 | 14303 | ||
14181 | spec->num_mux_defs = 1; | 14304 | spec->num_mux_defs = 1; |
14182 | spec->input_mux = &spec->private_imux[0]; | 14305 | spec->input_mux = &spec->private_imux[0]; |
14183 | fillup_priv_adc_nids(codec, alc269_adc_candidates, | 14306 | |
14184 | sizeof(alc269_adc_candidates)); | 14307 | if (!alc275_setup_dual_adc(codec)) |
14308 | fillup_priv_adc_nids(codec, alc269_adc_candidates, | ||
14309 | sizeof(alc269_adc_candidates)); | ||
14185 | 14310 | ||
14186 | /* set default input source */ | 14311 | /* set default input source */ |
14187 | snd_hda_codec_write_cache(codec, spec->capsrc_nids[0], | 14312 | if (!spec->dual_adc_switch) |
14313 | snd_hda_codec_write_cache(codec, spec->capsrc_nids[0], | ||
14188 | 0, AC_VERB_SET_CONNECT_SEL, | 14314 | 0, AC_VERB_SET_CONNECT_SEL, |
14189 | spec->input_mux->items[0].index); | 14315 | spec->input_mux->items[0].index); |
14190 | 14316 | ||
@@ -14480,6 +14606,10 @@ static int patch_alc269(struct hda_codec *codec) | |||
14480 | */ | 14606 | */ |
14481 | spec->stream_analog_playback = &alc269_44k_pcm_analog_playback; | 14607 | spec->stream_analog_playback = &alc269_44k_pcm_analog_playback; |
14482 | spec->stream_analog_capture = &alc269_44k_pcm_analog_capture; | 14608 | spec->stream_analog_capture = &alc269_44k_pcm_analog_capture; |
14609 | } else if (spec->dual_adc_switch) { | ||
14610 | spec->stream_analog_playback = &alc269_pcm_analog_playback; | ||
14611 | /* switch ADC dynamically */ | ||
14612 | spec->stream_analog_capture = &dualmic_pcm_analog_capture; | ||
14483 | } else { | 14613 | } else { |
14484 | spec->stream_analog_playback = &alc269_pcm_analog_playback; | 14614 | spec->stream_analog_playback = &alc269_pcm_analog_playback; |
14485 | spec->stream_analog_capture = &alc269_pcm_analog_capture; | 14615 | spec->stream_analog_capture = &alc269_pcm_analog_capture; |