diff options
author | Takashi Iwai <tiwai@suse.de> | 2011-11-07 11:13:39 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2011-11-08 02:59:36 -0500 |
commit | 24de183ed0369d73af89e6752fcc1ecbde59053d (patch) | |
tree | 328eeda01abff20d263ad841533af7f6ba133015 | |
parent | 82e14a4754599952f5504c1f696bbc77bdfd6009 (diff) |
ALSA: hda/realtek - Add the support of shared HP/Mic
A machine like Q1-ultra which has only a single HP but no mic-jack, we
can re-task the headhpone as an external mic jack. This was done formerly
in ALC262 model=ultra quirk, and now the auto-parser supports this mode.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 65 |
1 files changed, 64 insertions, 1 deletions
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 1f3d1686db1a..ef040ec6580d 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -183,6 +183,7 @@ struct alc_spec { | |||
183 | unsigned int single_input_src:1; | 183 | unsigned int single_input_src:1; |
184 | unsigned int vol_in_capsrc:1; /* use capsrc volume (ADC has no vol) */ | 184 | unsigned int vol_in_capsrc:1; /* use capsrc volume (ADC has no vol) */ |
185 | unsigned int parse_flags; /* passed to snd_hda_parse_pin_defcfg() */ | 185 | unsigned int parse_flags; /* passed to snd_hda_parse_pin_defcfg() */ |
186 | unsigned int shared_mic_hp:1; /* HP/Mic-in sharing */ | ||
186 | 187 | ||
187 | /* auto-mute control */ | 188 | /* auto-mute control */ |
188 | int automute_mode; | 189 | int automute_mode; |
@@ -277,6 +278,8 @@ static bool alc_dyn_adc_pcm_resetup(struct hda_codec *codec, int cur) | |||
277 | return false; | 278 | return false; |
278 | } | 279 | } |
279 | 280 | ||
281 | static void call_update_outputs(struct hda_codec *codec); | ||
282 | |||
280 | /* select the given imux item; either unmute exclusively or select the route */ | 283 | /* select the given imux item; either unmute exclusively or select the route */ |
281 | static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx, | 284 | static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx, |
282 | unsigned int idx, bool force) | 285 | unsigned int idx, bool force) |
@@ -298,6 +301,19 @@ static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx, | |||
298 | return 0; | 301 | return 0; |
299 | spec->cur_mux[adc_idx] = idx; | 302 | spec->cur_mux[adc_idx] = idx; |
300 | 303 | ||
304 | /* for shared I/O, change the pin-control accordingly */ | ||
305 | if (spec->shared_mic_hp) { | ||
306 | /* NOTE: this assumes that there are only two inputs, the | ||
307 | * first is the real internal mic and the second is HP jack. | ||
308 | */ | ||
309 | snd_hda_codec_write(codec, spec->autocfg.inputs[1].pin, 0, | ||
310 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
311 | spec->cur_mux[adc_idx] ? | ||
312 | PIN_VREF80 : PIN_HP); | ||
313 | spec->automute_speaker = !spec->cur_mux[adc_idx]; | ||
314 | call_update_outputs(codec); | ||
315 | } | ||
316 | |||
301 | if (spec->dyn_adc_switch) { | 317 | if (spec->dyn_adc_switch) { |
302 | alc_dyn_adc_pcm_resetup(codec, idx); | 318 | alc_dyn_adc_pcm_resetup(codec, idx); |
303 | adc_idx = spec->dyn_adc_idx[idx]; | 319 | adc_idx = spec->dyn_adc_idx[idx]; |
@@ -547,7 +563,8 @@ static void update_outputs(struct hda_codec *codec) | |||
547 | * in general, HP pins/amps control should be enabled in all cases, | 563 | * in general, HP pins/amps control should be enabled in all cases, |
548 | * but currently set only for master_mute, just to be safe | 564 | * but currently set only for master_mute, just to be safe |
549 | */ | 565 | */ |
550 | do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins), | 566 | if (!spec->shared_mic_hp) /* don't change HP-pin when shared with mic */ |
567 | do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins), | ||
551 | spec->autocfg.hp_pins, spec->master_mute, true); | 568 | spec->autocfg.hp_pins, spec->master_mute, true); |
552 | 569 | ||
553 | if (!spec->automute_speaker) | 570 | if (!spec->automute_speaker) |
@@ -1115,6 +1132,9 @@ static void alc_init_auto_mic(struct hda_codec *codec) | |||
1115 | hda_nid_t fixed, ext, dock; | 1132 | hda_nid_t fixed, ext, dock; |
1116 | int i; | 1133 | int i; |
1117 | 1134 | ||
1135 | if (spec->shared_mic_hp) | ||
1136 | return; /* no auto-mic for the shared I/O */ | ||
1137 | |||
1118 | spec->ext_mic_idx = spec->int_mic_idx = spec->dock_mic_idx = -1; | 1138 | spec->ext_mic_idx = spec->int_mic_idx = spec->dock_mic_idx = -1; |
1119 | 1139 | ||
1120 | fixed = ext = dock = 0; | 1140 | fixed = ext = dock = 0; |
@@ -2667,6 +2687,9 @@ static int alc_auto_fill_adc_caps(struct hda_codec *codec) | |||
2667 | int max_nums = ARRAY_SIZE(spec->private_adc_nids); | 2687 | int max_nums = ARRAY_SIZE(spec->private_adc_nids); |
2668 | int i, nums = 0; | 2688 | int i, nums = 0; |
2669 | 2689 | ||
2690 | if (spec->shared_mic_hp) | ||
2691 | max_nums = 1; /* no multi streams with the shared HP/mic */ | ||
2692 | |||
2670 | nid = codec->start_nid; | 2693 | nid = codec->start_nid; |
2671 | for (i = 0; i < codec->num_nodes; i++, nid++) { | 2694 | for (i = 0; i < codec->num_nodes; i++, nid++) { |
2672 | hda_nid_t src; | 2695 | hda_nid_t src; |
@@ -2729,6 +2752,8 @@ static int alc_auto_create_input_ctls(struct hda_codec *codec) | |||
2729 | continue; | 2752 | continue; |
2730 | 2753 | ||
2731 | label = hda_get_autocfg_input_label(codec, cfg, i); | 2754 | label = hda_get_autocfg_input_label(codec, cfg, i); |
2755 | if (spec->shared_mic_hp && !strcmp(label, "Misc")) | ||
2756 | label = "Headphone Mic"; | ||
2732 | if (prev_label && !strcmp(label, prev_label)) | 2757 | if (prev_label && !strcmp(label, prev_label)) |
2733 | type_idx++; | 2758 | type_idx++; |
2734 | else | 2759 | else |
@@ -2764,6 +2789,39 @@ static int alc_auto_create_input_ctls(struct hda_codec *codec) | |||
2764 | return 0; | 2789 | return 0; |
2765 | } | 2790 | } |
2766 | 2791 | ||
2792 | /* create a shared input with the headphone out */ | ||
2793 | static int alc_auto_create_shared_input(struct hda_codec *codec) | ||
2794 | { | ||
2795 | struct alc_spec *spec = codec->spec; | ||
2796 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
2797 | unsigned int defcfg; | ||
2798 | hda_nid_t nid; | ||
2799 | |||
2800 | /* only one internal input pin? */ | ||
2801 | if (cfg->num_inputs != 1) | ||
2802 | return 0; | ||
2803 | defcfg = snd_hda_codec_get_pincfg(codec, cfg->inputs[0].pin); | ||
2804 | if (snd_hda_get_input_pin_attr(defcfg) != INPUT_PIN_ATTR_INT) | ||
2805 | return 0; | ||
2806 | |||
2807 | if (cfg->hp_outs == 1 && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) | ||
2808 | nid = cfg->hp_pins[0]; /* OK, we have a single HP-out */ | ||
2809 | else if (cfg->line_outs == 1 && cfg->line_out_type == AUTO_PIN_HP_OUT) | ||
2810 | nid = cfg->line_out_pins[0]; /* OK, we have a single line-out */ | ||
2811 | else | ||
2812 | return 0; /* both not available */ | ||
2813 | |||
2814 | if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_IN)) | ||
2815 | return 0; /* no input */ | ||
2816 | |||
2817 | cfg->inputs[1].pin = nid; | ||
2818 | cfg->inputs[1].type = AUTO_PIN_MIC; | ||
2819 | cfg->num_inputs = 2; | ||
2820 | spec->shared_mic_hp = 1; | ||
2821 | snd_printdd("realtek: Enable shared I/O jack on NID 0x%x\n", nid); | ||
2822 | return 0; | ||
2823 | } | ||
2824 | |||
2767 | static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid, | 2825 | static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid, |
2768 | unsigned int pin_type) | 2826 | unsigned int pin_type) |
2769 | { | 2827 | { |
@@ -3654,6 +3712,8 @@ static int alc_auto_add_mic_boost(struct hda_codec *codec) | |||
3654 | char boost_label[32]; | 3712 | char boost_label[32]; |
3655 | 3713 | ||
3656 | label = hda_get_autocfg_input_label(codec, cfg, i); | 3714 | label = hda_get_autocfg_input_label(codec, cfg, i); |
3715 | if (spec->shared_mic_hp && !strcmp(label, "Misc")) | ||
3716 | label = "Headphone Mic"; | ||
3657 | if (prev_label && !strcmp(label, prev_label)) | 3717 | if (prev_label && !strcmp(label, prev_label)) |
3658 | type_idx++; | 3718 | type_idx++; |
3659 | else | 3719 | else |
@@ -3859,6 +3919,9 @@ static int alc_parse_auto_config(struct hda_codec *codec, | |||
3859 | err = alc_auto_create_speaker_out(codec); | 3919 | err = alc_auto_create_speaker_out(codec); |
3860 | if (err < 0) | 3920 | if (err < 0) |
3861 | return err; | 3921 | return err; |
3922 | err = alc_auto_create_shared_input(codec); | ||
3923 | if (err < 0) | ||
3924 | return err; | ||
3862 | err = alc_auto_create_input_ctls(codec); | 3925 | err = alc_auto_create_input_ctls(codec); |
3863 | if (err < 0) | 3926 | if (err < 0) |
3864 | return err; | 3927 | return err; |