diff options
author | Takashi Iwai <tiwai@suse.de> | 2013-02-19 11:12:42 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2013-03-07 12:29:52 -0500 |
commit | 967303dabc22335e83c6ee4a9e0684a7c05da976 (patch) | |
tree | f94d11ae35522d65fb437812ca6190a31775bcfd | |
parent | 2dad9402192250d4061332b6a9be71ebf8493c49 (diff) |
ALSA: hda - Add the generic Headphone Mic feature
This patch improves the generic parser code to allow to set up the
headphone jack as a mic input. User can enable this feature by giving
hp_mic hint string.
The former shared hp/mic feature for the single built-in mic is still
retained. This detection can be disabled now via hp_mic_detect hint
string, too.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r-- | Documentation/sound/alsa/HD-Audio.txt | 3 | ||||
-rw-r--r-- | sound/pci/hda/hda_generic.c | 143 | ||||
-rw-r--r-- | sound/pci/hda/hda_generic.h | 6 |
3 files changed, 97 insertions, 55 deletions
diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt index d4faa63ff352..77e176a35ce1 100644 --- a/Documentation/sound/alsa/HD-Audio.txt +++ b/Documentation/sound/alsa/HD-Audio.txt | |||
@@ -466,6 +466,9 @@ The generic parser supports the following hints: | |||
466 | - add_in_jack_modes (bool): add "xxx Jack Mode" enum controls to each | 466 | - add_in_jack_modes (bool): add "xxx Jack Mode" enum controls to each |
467 | input jack for allowing to change the mic bias vref | 467 | input jack for allowing to change the mic bias vref |
468 | - power_down_unused (bool): power down the unused widgets | 468 | - power_down_unused (bool): power down the unused widgets |
469 | - add_hp_mic (bool): add the headphone to capture source if possible | ||
470 | - hp_mic_detect (bool): enable/disable the hp/mic shared input for a | ||
471 | single built-in mic case; default true | ||
469 | - mixer_nid (int): specifies the widget NID of the analog-loopback | 472 | - mixer_nid (int): specifies the widget NID of the analog-loopback |
470 | mixer | 473 | mixer |
471 | 474 | ||
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 78897d05d80f..73de215da03f 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c | |||
@@ -159,6 +159,12 @@ static void parse_user_hints(struct hda_codec *codec) | |||
159 | val = snd_hda_get_bool_hint(codec, "power_down_unused"); | 159 | val = snd_hda_get_bool_hint(codec, "power_down_unused"); |
160 | if (val >= 0) | 160 | if (val >= 0) |
161 | spec->power_down_unused = !!val; | 161 | spec->power_down_unused = !!val; |
162 | val = snd_hda_get_bool_hint(codec, "add_hp_mic"); | ||
163 | if (val >= 0) | ||
164 | spec->hp_mic = !!val; | ||
165 | val = snd_hda_get_bool_hint(codec, "hp_mic_detect"); | ||
166 | if (val >= 0) | ||
167 | spec->suppress_hp_mic_detect = !val; | ||
162 | 168 | ||
163 | if (!snd_hda_get_int_hint(codec, "mixer_nid", &val)) | 169 | if (!snd_hda_get_int_hint(codec, "mixer_nid", &val)) |
164 | spec->mixer_nid = val; | 170 | spec->mixer_nid = val; |
@@ -2194,63 +2200,97 @@ static int create_loopback_mixing_ctl(struct hda_codec *codec) | |||
2194 | static void call_update_outputs(struct hda_codec *codec); | 2200 | static void call_update_outputs(struct hda_codec *codec); |
2195 | 2201 | ||
2196 | /* for shared I/O, change the pin-control accordingly */ | 2202 | /* for shared I/O, change the pin-control accordingly */ |
2197 | static void update_shared_mic_hp(struct hda_codec *codec, bool set_as_mic) | 2203 | static void update_hp_mic(struct hda_codec *codec, int adc_mux, bool force) |
2198 | { | 2204 | { |
2199 | struct hda_gen_spec *spec = codec->spec; | 2205 | struct hda_gen_spec *spec = codec->spec; |
2206 | bool as_mic; | ||
2200 | unsigned int val; | 2207 | unsigned int val; |
2201 | hda_nid_t pin = spec->autocfg.inputs[1].pin; | 2208 | hda_nid_t pin; |
2202 | /* NOTE: this assumes that there are only two inputs, the | ||
2203 | * first is the real internal mic and the second is HP/mic jack. | ||
2204 | */ | ||
2205 | 2209 | ||
2206 | val = snd_hda_get_default_vref(codec, pin); | 2210 | pin = spec->hp_mic_pin; |
2211 | as_mic = spec->cur_mux[adc_mux] == spec->hp_mic_mux_idx; | ||
2207 | 2212 | ||
2208 | /* This pin does not have vref caps - let's enable vref on pin 0x18 | 2213 | if (!force) { |
2209 | instead, as suggested by Realtek */ | 2214 | val = snd_hda_codec_get_pin_target(codec, pin); |
2215 | if (as_mic) { | ||
2216 | if (val & PIN_IN) | ||
2217 | return; | ||
2218 | } else { | ||
2219 | if (val & PIN_OUT) | ||
2220 | return; | ||
2221 | } | ||
2222 | } | ||
2223 | |||
2224 | val = snd_hda_get_default_vref(codec, pin); | ||
2225 | /* if the HP pin doesn't support VREF and the codec driver gives an | ||
2226 | * alternative pin, set up the VREF on that pin instead | ||
2227 | */ | ||
2210 | if (val == AC_PINCTL_VREF_HIZ && spec->shared_mic_vref_pin) { | 2228 | if (val == AC_PINCTL_VREF_HIZ && spec->shared_mic_vref_pin) { |
2211 | const hda_nid_t vref_pin = spec->shared_mic_vref_pin; | 2229 | const hda_nid_t vref_pin = spec->shared_mic_vref_pin; |
2212 | unsigned int vref_val = snd_hda_get_default_vref(codec, vref_pin); | 2230 | unsigned int vref_val = snd_hda_get_default_vref(codec, vref_pin); |
2213 | if (vref_val != AC_PINCTL_VREF_HIZ) | 2231 | if (vref_val != AC_PINCTL_VREF_HIZ) |
2214 | snd_hda_set_pin_ctl_cache(codec, vref_pin, | 2232 | snd_hda_set_pin_ctl_cache(codec, vref_pin, |
2215 | PIN_IN | (set_as_mic ? vref_val : 0)); | 2233 | PIN_IN | (as_mic ? vref_val : 0)); |
2216 | } | 2234 | } |
2217 | 2235 | ||
2218 | val = set_as_mic ? val | PIN_IN : PIN_HP; | 2236 | if (as_mic) |
2237 | val |= PIN_IN; | ||
2238 | else | ||
2239 | val = PIN_HP; | ||
2219 | set_pin_target(codec, pin, val, true); | 2240 | set_pin_target(codec, pin, val, true); |
2220 | 2241 | ||
2221 | spec->automute_speaker = !set_as_mic; | 2242 | /* update HP auto-mute state too */ |
2222 | call_update_outputs(codec); | 2243 | if (spec->hp_automute_hook) |
2244 | spec->hp_automute_hook(codec, NULL); | ||
2245 | else | ||
2246 | snd_hda_gen_hp_automute(codec, NULL); | ||
2223 | } | 2247 | } |
2224 | 2248 | ||
2225 | /* create a shared input with the headphone out */ | 2249 | /* create a shared input with the headphone out */ |
2226 | static int create_shared_input(struct hda_codec *codec) | 2250 | static int create_hp_mic(struct hda_codec *codec) |
2227 | { | 2251 | { |
2228 | struct hda_gen_spec *spec = codec->spec; | 2252 | struct hda_gen_spec *spec = codec->spec; |
2229 | struct auto_pin_cfg *cfg = &spec->autocfg; | 2253 | struct auto_pin_cfg *cfg = &spec->autocfg; |
2230 | unsigned int defcfg; | 2254 | unsigned int defcfg; |
2231 | hda_nid_t nid; | 2255 | hda_nid_t nid; |
2232 | 2256 | ||
2233 | /* only one internal input pin? */ | 2257 | if (!spec->hp_mic) { |
2234 | if (cfg->num_inputs != 1) | 2258 | if (spec->suppress_hp_mic_detect) |
2235 | return 0; | 2259 | return 0; |
2236 | defcfg = snd_hda_codec_get_pincfg(codec, cfg->inputs[0].pin); | 2260 | /* automatic detection: only if no input or a single internal |
2237 | if (snd_hda_get_input_pin_attr(defcfg) != INPUT_PIN_ATTR_INT) | 2261 | * input pin is found, try to detect the shared hp/mic |
2262 | */ | ||
2263 | if (cfg->num_inputs > 1) | ||
2264 | return 0; | ||
2265 | else if (cfg->num_inputs == 1) { | ||
2266 | defcfg = snd_hda_codec_get_pincfg(codec, cfg->inputs[0].pin); | ||
2267 | if (snd_hda_get_input_pin_attr(defcfg) != INPUT_PIN_ATTR_INT) | ||
2268 | return 0; | ||
2269 | } | ||
2270 | } | ||
2271 | |||
2272 | spec->hp_mic = 0; /* clear once */ | ||
2273 | if (cfg->num_inputs >= AUTO_CFG_MAX_INS) | ||
2238 | return 0; | 2274 | return 0; |
2239 | 2275 | ||
2240 | if (cfg->hp_outs == 1 && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) | 2276 | nid = 0; |
2241 | nid = cfg->hp_pins[0]; /* OK, we have a single HP-out */ | 2277 | if (cfg->line_out_type == AUTO_PIN_HP_OUT && cfg->line_outs > 0) |
2242 | else if (cfg->line_outs == 1 && cfg->line_out_type == AUTO_PIN_HP_OUT) | 2278 | nid = cfg->line_out_pins[0]; |
2243 | nid = cfg->line_out_pins[0]; /* OK, we have a single line-out */ | 2279 | else if (cfg->hp_outs > 0) |
2244 | else | 2280 | nid = cfg->hp_pins[0]; |
2245 | return 0; /* both not available */ | 2281 | if (!nid) |
2282 | return 0; | ||
2246 | 2283 | ||
2247 | if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_IN)) | 2284 | if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_IN)) |
2248 | return 0; /* no input */ | 2285 | return 0; /* no input */ |
2249 | 2286 | ||
2250 | cfg->inputs[1].pin = nid; | 2287 | cfg->inputs[cfg->num_inputs].pin = nid; |
2251 | cfg->inputs[1].type = AUTO_PIN_MIC; | 2288 | cfg->inputs[cfg->num_inputs].type = AUTO_PIN_MIC; |
2252 | cfg->num_inputs = 2; | 2289 | cfg->num_inputs++; |
2253 | spec->shared_mic_hp = 1; | 2290 | spec->hp_mic = 1; |
2291 | spec->hp_mic_pin = nid; | ||
2292 | /* we can't handle auto-mic together with HP-mic */ | ||
2293 | spec->suppress_auto_mic = 1; | ||
2254 | snd_printdd("hda-codec: Enable shared I/O jack on NID 0x%x\n", nid); | 2294 | snd_printdd("hda-codec: Enable shared I/O jack on NID 0x%x\n", nid); |
2255 | return 0; | 2295 | return 0; |
2256 | } | 2296 | } |
@@ -2602,7 +2642,6 @@ static int check_dyn_adc_switch(struct hda_codec *codec) | |||
2602 | unsigned int ok_bits; | 2642 | unsigned int ok_bits; |
2603 | int i, n, nums; | 2643 | int i, n, nums; |
2604 | 2644 | ||
2605 | again: | ||
2606 | nums = 0; | 2645 | nums = 0; |
2607 | ok_bits = 0; | 2646 | ok_bits = 0; |
2608 | for (n = 0; n < spec->num_adc_nids; n++) { | 2647 | for (n = 0; n < spec->num_adc_nids; n++) { |
@@ -2617,12 +2656,6 @@ static int check_dyn_adc_switch(struct hda_codec *codec) | |||
2617 | } | 2656 | } |
2618 | 2657 | ||
2619 | if (!ok_bits) { | 2658 | if (!ok_bits) { |
2620 | if (spec->shared_mic_hp) { | ||
2621 | spec->shared_mic_hp = 0; | ||
2622 | imux->num_items = 1; | ||
2623 | goto again; | ||
2624 | } | ||
2625 | |||
2626 | /* check whether ADC-switch is possible */ | 2659 | /* check whether ADC-switch is possible */ |
2627 | for (i = 0; i < imux->num_items; i++) { | 2660 | for (i = 0; i < imux->num_items; i++) { |
2628 | for (n = 0; n < spec->num_adc_nids; n++) { | 2661 | for (n = 0; n < spec->num_adc_nids; n++) { |
@@ -2655,7 +2688,8 @@ static int check_dyn_adc_switch(struct hda_codec *codec) | |||
2655 | spec->num_adc_nids = nums; | 2688 | spec->num_adc_nids = nums; |
2656 | } | 2689 | } |
2657 | 2690 | ||
2658 | if (imux->num_items == 1 || spec->shared_mic_hp) { | 2691 | if (imux->num_items == 1 || |
2692 | (imux->num_items == 2 && spec->hp_mic)) { | ||
2659 | snd_printdd("hda-codec: reducing to a single ADC\n"); | 2693 | snd_printdd("hda-codec: reducing to a single ADC\n"); |
2660 | spec->num_adc_nids = 1; /* reduce to a single ADC */ | 2694 | spec->num_adc_nids = 1; /* reduce to a single ADC */ |
2661 | } | 2695 | } |
@@ -2692,6 +2726,8 @@ static int parse_capture_source(struct hda_codec *codec, hda_nid_t pin, | |||
2692 | snd_hda_get_path_idx(codec, path); | 2726 | snd_hda_get_path_idx(codec, path); |
2693 | 2727 | ||
2694 | if (!imux_added) { | 2728 | if (!imux_added) { |
2729 | if (spec->hp_mic_pin == pin) | ||
2730 | spec->hp_mic_mux_idx = imux->num_items; | ||
2695 | spec->imux_pins[imux->num_items] = pin; | 2731 | spec->imux_pins[imux->num_items] = pin; |
2696 | snd_hda_add_imux_item(imux, label, cfg_idx, NULL); | 2732 | snd_hda_add_imux_item(imux, label, cfg_idx, NULL); |
2697 | imux_added = true; | 2733 | imux_added = true; |
@@ -3416,8 +3452,8 @@ static int mux_select(struct hda_codec *codec, unsigned int adc_idx, | |||
3416 | 3452 | ||
3417 | spec->cur_mux[adc_idx] = idx; | 3453 | spec->cur_mux[adc_idx] = idx; |
3418 | 3454 | ||
3419 | if (spec->shared_mic_hp) | 3455 | if (spec->hp_mic) |
3420 | update_shared_mic_hp(codec, spec->cur_mux[adc_idx]); | 3456 | update_hp_mic(codec, adc_idx, false); |
3421 | 3457 | ||
3422 | if (spec->dyn_adc_switch) | 3458 | if (spec->dyn_adc_switch) |
3423 | dyn_adc_pcm_resetup(codec, idx); | 3459 | dyn_adc_pcm_resetup(codec, idx); |
@@ -3465,18 +3501,21 @@ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, | |||
3465 | 3501 | ||
3466 | for (i = 0; i < num_pins; i++) { | 3502 | for (i = 0; i < num_pins; i++) { |
3467 | hda_nid_t nid = pins[i]; | 3503 | hda_nid_t nid = pins[i]; |
3468 | unsigned int val; | 3504 | unsigned int val, oldval; |
3469 | if (!nid) | 3505 | if (!nid) |
3470 | break; | 3506 | break; |
3507 | oldval = snd_hda_codec_get_pin_target(codec, nid); | ||
3508 | if (oldval & PIN_IN) | ||
3509 | continue; /* no mute for inputs */ | ||
3471 | /* don't reset VREF value in case it's controlling | 3510 | /* don't reset VREF value in case it's controlling |
3472 | * the amp (see alc861_fixup_asus_amp_vref_0f()) | 3511 | * the amp (see alc861_fixup_asus_amp_vref_0f()) |
3473 | */ | 3512 | */ |
3474 | if (spec->keep_vref_in_automute) | 3513 | if (spec->keep_vref_in_automute) |
3475 | val = snd_hda_codec_get_pin_target(codec, nid) & ~PIN_HP; | 3514 | val = oldval & ~PIN_HP; |
3476 | else | 3515 | else |
3477 | val = 0; | 3516 | val = 0; |
3478 | if (!mute) | 3517 | if (!mute) |
3479 | val |= snd_hda_codec_get_pin_target(codec, nid); | 3518 | val |= oldval; |
3480 | /* here we call update_pin_ctl() so that the pinctl is changed | 3519 | /* here we call update_pin_ctl() so that the pinctl is changed |
3481 | * without changing the pinctl target value; | 3520 | * without changing the pinctl target value; |
3482 | * the original target value will be still referred at the | 3521 | * the original target value will be still referred at the |
@@ -3497,8 +3536,7 @@ void snd_hda_gen_update_outputs(struct hda_codec *codec) | |||
3497 | * in general, HP pins/amps control should be enabled in all cases, | 3536 | * in general, HP pins/amps control should be enabled in all cases, |
3498 | * but currently set only for master_mute, just to be safe | 3537 | * but currently set only for master_mute, just to be safe |
3499 | */ | 3538 | */ |
3500 | if (!spec->shared_mic_hp) /* don't change HP-pin when shared with mic */ | 3539 | do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins), |
3501 | do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins), | ||
3502 | spec->autocfg.hp_pins, spec->master_mute); | 3540 | spec->autocfg.hp_pins, spec->master_mute); |
3503 | 3541 | ||
3504 | if (!spec->automute_speaker) | 3542 | if (!spec->automute_speaker) |
@@ -3978,7 +4016,7 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec, | |||
3978 | err = create_loopback_mixing_ctl(codec); | 4016 | err = create_loopback_mixing_ctl(codec); |
3979 | if (err < 0) | 4017 | if (err < 0) |
3980 | return err; | 4018 | return err; |
3981 | err = create_shared_input(codec); | 4019 | err = create_hp_mic(codec); |
3982 | if (err < 0) | 4020 | if (err < 0) |
3983 | return err; | 4021 | return err; |
3984 | err = create_input_ctls(codec); | 4022 | err = create_input_ctls(codec); |
@@ -4004,11 +4042,9 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec, | |||
4004 | if (err < 0) | 4042 | if (err < 0) |
4005 | return err; | 4043 | return err; |
4006 | 4044 | ||
4007 | if (!spec->shared_mic_hp) { | 4045 | err = check_auto_mic_availability(codec); |
4008 | err = check_auto_mic_availability(codec); | 4046 | if (err < 0) |
4009 | if (err < 0) | 4047 | return err; |
4010 | return err; | ||
4011 | } | ||
4012 | 4048 | ||
4013 | err = create_capture_mixers(codec); | 4049 | err = create_capture_mixers(codec); |
4014 | if (err < 0) | 4050 | if (err < 0) |
@@ -4115,9 +4151,9 @@ int snd_hda_gen_build_controls(struct hda_codec *codec) | |||
4115 | 4151 | ||
4116 | free_kctls(spec); /* no longer needed */ | 4152 | free_kctls(spec); /* no longer needed */ |
4117 | 4153 | ||
4118 | if (spec->shared_mic_hp) { | 4154 | if (spec->hp_mic_pin) { |
4119 | int err; | 4155 | int err; |
4120 | int nid = spec->autocfg.inputs[1].pin; | 4156 | int nid = spec->hp_mic_pin; |
4121 | err = snd_hda_jack_add_kctl(codec, nid, "Headphone Mic", 0); | 4157 | err = snd_hda_jack_add_kctl(codec, nid, "Headphone Mic", 0); |
4122 | if (err < 0) | 4158 | if (err < 0) |
4123 | return err; | 4159 | return err; |
@@ -4780,11 +4816,10 @@ static void init_input_src(struct hda_codec *codec) | |||
4780 | snd_hda_activate_path(codec, path, active, false); | 4816 | snd_hda_activate_path(codec, path, active, false); |
4781 | } | 4817 | } |
4782 | } | 4818 | } |
4819 | if (spec->hp_mic) | ||
4820 | update_hp_mic(codec, c, true); | ||
4783 | } | 4821 | } |
4784 | 4822 | ||
4785 | if (spec->shared_mic_hp) | ||
4786 | update_shared_mic_hp(codec, spec->cur_mux[0]); | ||
4787 | |||
4788 | if (spec->cap_sync_hook) | 4823 | if (spec->cap_sync_hook) |
4789 | spec->cap_sync_hook(codec, NULL); | 4824 | spec->cap_sync_hook(codec, NULL); |
4790 | } | 4825 | } |
diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h index 009b57be96d3..7ee5b57946c9 100644 --- a/sound/pci/hda/hda_generic.h +++ b/sound/pci/hda/hda_generic.h | |||
@@ -145,7 +145,10 @@ struct hda_gen_spec { | |||
145 | hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; | 145 | hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; |
146 | hda_nid_t imux_pins[HDA_MAX_NUM_INPUTS]; | 146 | hda_nid_t imux_pins[HDA_MAX_NUM_INPUTS]; |
147 | unsigned int dyn_adc_idx[HDA_MAX_NUM_INPUTS]; | 147 | unsigned int dyn_adc_idx[HDA_MAX_NUM_INPUTS]; |
148 | /* shared hp/mic */ | ||
148 | hda_nid_t shared_mic_vref_pin; | 149 | hda_nid_t shared_mic_vref_pin; |
150 | hda_nid_t hp_mic_pin; | ||
151 | int hp_mic_mux_idx; | ||
149 | 152 | ||
150 | /* DAC/ADC lists */ | 153 | /* DAC/ADC lists */ |
151 | int num_all_dacs; | 154 | int num_all_dacs; |
@@ -200,7 +203,8 @@ struct hda_gen_spec { | |||
200 | 203 | ||
201 | /* other parse behavior flags */ | 204 | /* other parse behavior flags */ |
202 | unsigned int need_dac_fix:1; /* need to limit DACs for multi channels */ | 205 | unsigned int need_dac_fix:1; /* need to limit DACs for multi channels */ |
203 | unsigned int shared_mic_hp:1; /* HP/Mic-in sharing */ | 206 | unsigned int hp_mic:1; /* Allow HP as a mic-in */ |
207 | unsigned int suppress_hp_mic_detect:1; /* Don't detect HP/mic */ | ||
204 | unsigned int no_primary_hp:1; /* Don't prefer HP pins to speaker pins */ | 208 | unsigned int no_primary_hp:1; /* Don't prefer HP pins to speaker pins */ |
205 | unsigned int multi_cap_vol:1; /* allow multiple capture xxx volumes */ | 209 | unsigned int multi_cap_vol:1; /* allow multiple capture xxx volumes */ |
206 | unsigned int inv_dmic_split:1; /* inverted dmic w/a for conexant */ | 210 | unsigned int inv_dmic_split:1; /* inverted dmic w/a for conexant */ |