aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2011-05-17 04:35:15 -0400
committerTakashi Iwai <tiwai@suse.de>2011-05-17 06:33:00 -0400
commit43c1b2e9209cc824177a5a13e34fb21dfab3455a (patch)
treea91f2d81088902097b3fd4ac5c1db665d5960021 /sound
parent52d3cb88d75701f800db16561ff12c7692b56e55 (diff)
ALSA: hda - Add support of dock-mic detection to Conexant auto-parser
In addition to the normal external mic jack, check also the mic jack on a docking-station as well, and select the input source appropriately. The similar functionality was already implemented in patch_sigmatel.c. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r--sound/pci/hda/patch_conexant.c98
1 files changed, 59 insertions, 39 deletions
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index ac595363e0e0..2a04fea01692 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -85,6 +85,8 @@ struct conexant_spec {
85 unsigned int line_present; 85 unsigned int line_present;
86 unsigned int auto_mic; 86 unsigned int auto_mic;
87 int auto_mic_ext; /* imux_pins[] index for ext mic */ 87 int auto_mic_ext; /* imux_pins[] index for ext mic */
88 int auto_mic_dock; /* imux_pins[] index for dock mic */
89 int auto_mic_int; /* imux_pins[] index for int mic */
88 unsigned int need_dac_fix; 90 unsigned int need_dac_fix;
89 hda_nid_t slave_dig_outs[2]; 91 hda_nid_t slave_dig_outs[2];
90 92
@@ -3737,18 +3739,27 @@ static const struct snd_kcontrol_new cx_auto_capture_mixers[] = {
3737 {} 3739 {}
3738}; 3740};
3739 3741
3742static bool select_automic(struct hda_codec *codec, int idx, bool detect)
3743{
3744 struct conexant_spec *spec = codec->spec;
3745 if (idx < 0)
3746 return false;
3747 if (detect && !snd_hda_jack_detect(codec, spec->imux_info[idx].pin))
3748 return false;
3749 cx_auto_mux_enum_update(codec, &spec->private_imux, idx);
3750 return true;
3751}
3752
3740/* automatic switch internal and external mic */ 3753/* automatic switch internal and external mic */
3741static void cx_auto_automic(struct hda_codec *codec) 3754static void cx_auto_automic(struct hda_codec *codec)
3742{ 3755{
3743 struct conexant_spec *spec = codec->spec; 3756 struct conexant_spec *spec = codec->spec;
3744 int ext_idx = spec->auto_mic_ext;
3745 3757
3746 if (!spec->auto_mic) 3758 if (!spec->auto_mic)
3747 return; 3759 return;
3748 if (snd_hda_jack_detect(codec, spec->imux_info[ext_idx].pin)) 3760 if (!select_automic(codec, spec->auto_mic_ext, true))
3749 cx_auto_mux_enum_update(codec, &spec->private_imux, ext_idx); 3761 if (!select_automic(codec, spec->auto_mic_dock, true))
3750 else 3762 select_automic(codec, spec->auto_mic_int, false);
3751 cx_auto_mux_enum_update(codec, &spec->private_imux, !ext_idx);
3752} 3763}
3753 3764
3754static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res) 3765static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res)
@@ -3768,42 +3779,43 @@ static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res)
3768 } 3779 }
3769} 3780}
3770 3781
3771/* return true if it's an internal-mic pin */
3772static int is_int_mic(struct hda_codec *codec, hda_nid_t pin)
3773{
3774 unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin);
3775 return get_defcfg_device(def_conf) == AC_JACK_MIC_IN &&
3776 snd_hda_get_input_pin_attr(def_conf) == INPUT_PIN_ATTR_INT;
3777}
3778
3779/* return true if it's an external-mic pin */
3780static int is_ext_mic(struct hda_codec *codec, hda_nid_t pin)
3781{
3782 unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin);
3783 return get_defcfg_device(def_conf) == AC_JACK_MIC_IN &&
3784 snd_hda_get_input_pin_attr(def_conf) >= INPUT_PIN_ATTR_NORMAL &&
3785 is_jack_detectable(codec, pin);
3786}
3787
3788/* check whether the pin config is suitable for auto-mic switching; 3782/* check whether the pin config is suitable for auto-mic switching;
3789 * auto-mic is enabled only when one int-mic and one-ext mic exist 3783 * auto-mic is enabled only when one int-mic and one ext- and/or
3784 * one dock-mic exist
3790 */ 3785 */
3791static void cx_auto_check_auto_mic(struct hda_codec *codec) 3786static void cx_auto_check_auto_mic(struct hda_codec *codec)
3792{ 3787{
3793 struct conexant_spec *spec = codec->spec; 3788 struct conexant_spec *spec = codec->spec;
3789 int pset[INPUT_PIN_ATTR_NORMAL + 1];
3790 int i;
3794 3791
3795 if (is_ext_mic(codec, spec->imux_info[0].pin) && 3792 for (i = 0; i < INPUT_PIN_ATTR_NORMAL; i++)
3796 is_int_mic(codec, spec->imux_info[1].pin)) { 3793 pset[i] = -1;
3797 spec->auto_mic = 1; 3794 for (i = 0; i < spec->private_imux.num_items; i++) {
3798 spec->auto_mic_ext = 0; 3795 hda_nid_t pin = spec->imux_info[i].pin;
3799 return; 3796 unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin);
3800 } 3797 int attr;
3801 if (is_int_mic(codec, spec->imux_info[0].pin) && 3798 if (get_defcfg_device(def_conf) != AC_JACK_MIC_IN)
3802 is_ext_mic(codec, spec->imux_info[1].pin)) { 3799 return; /* no-mic input */
3803 spec->auto_mic = 1; 3800 attr = snd_hda_get_input_pin_attr(def_conf);
3804 spec->auto_mic_ext = 1; 3801 if (attr == INPUT_PIN_ATTR_UNUSED)
3805 return; 3802 continue;
3803 if (attr > INPUT_PIN_ATTR_NORMAL)
3804 attr = INPUT_PIN_ATTR_NORMAL;
3805 if (attr != INPUT_PIN_ATTR_INT &&
3806 !is_jack_detectable(codec, pin))
3807 continue;
3808 if (pset[attr] >= 0)
3809 return; /* already occupied */
3810 pset[attr] = i;
3806 } 3811 }
3812 if (pset[INPUT_PIN_ATTR_INT] < 0 ||
3813 (pset[INPUT_PIN_ATTR_NORMAL] < 0 && pset[INPUT_PIN_ATTR_DOCK]))
3814 return; /* no input to switch*/
3815 spec->auto_mic = 1;
3816 spec->auto_mic_ext = pset[INPUT_PIN_ATTR_NORMAL];
3817 spec->auto_mic_dock = pset[INPUT_PIN_ATTR_DOCK];
3818 spec->auto_mic_int = pset[INPUT_PIN_ATTR_INT];
3807} 3819}
3808 3820
3809static void cx_auto_parse_input(struct hda_codec *codec) 3821static void cx_auto_parse_input(struct hda_codec *codec)
@@ -3832,7 +3844,7 @@ static void cx_auto_parse_input(struct hda_codec *codec)
3832 } 3844 }
3833 } 3845 }
3834 } 3846 }
3835 if (imux->num_items == 2 && cfg->num_inputs == 2) 3847 if (imux->num_items >= 2 && cfg->num_inputs == imux->num_items)
3836 cx_auto_check_auto_mic(codec); 3848 cx_auto_check_auto_mic(codec);
3837 if (imux->num_items > 1 && !spec->auto_mic) { 3849 if (imux->num_items > 1 && !spec->auto_mic) {
3838 for (i = 1; i < imux->num_items; i++) { 3850 for (i = 1; i < imux->num_items; i++) {
@@ -4022,10 +4034,18 @@ static void cx_auto_init_input(struct hda_codec *codec)
4022 } 4034 }
4023 4035
4024 if (spec->auto_mic) { 4036 if (spec->auto_mic) {
4025 int ext_idx = spec->auto_mic_ext; 4037 if (spec->auto_mic_ext >= 0) {
4026 snd_hda_codec_write(codec, cfg->inputs[ext_idx].pin, 0, 4038 snd_hda_codec_write(codec,
4027 AC_VERB_SET_UNSOLICITED_ENABLE, 4039 cfg->inputs[spec->auto_mic_ext].pin, 0,
4028 AC_USRSP_EN | CONEXANT_MIC_EVENT); 4040 AC_VERB_SET_UNSOLICITED_ENABLE,
4041 AC_USRSP_EN | CONEXANT_MIC_EVENT);
4042 }
4043 if (spec->auto_mic_dock >= 0) {
4044 snd_hda_codec_write(codec,
4045 cfg->inputs[spec->auto_mic_dock].pin, 0,
4046 AC_VERB_SET_UNSOLICITED_ENABLE,
4047 AC_USRSP_EN | CONEXANT_MIC_EVENT);
4048 }
4029 cx_auto_automic(codec); 4049 cx_auto_automic(codec);
4030 } else { 4050 } else {
4031 select_input_connection(codec, spec->imux_info[0].adc, 4051 select_input_connection(codec, spec->imux_info[0].adc,