diff options
Diffstat (limited to 'sound/pci/hda/patch_analog.c')
-rw-r--r-- | sound/pci/hda/patch_analog.c | 131 |
1 files changed, 90 insertions, 41 deletions
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 403588c6e3f6..215e72a87113 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c | |||
@@ -2982,7 +2982,8 @@ static int patch_ad1988(struct hda_codec *codec) | |||
2982 | board_config = snd_hda_check_board_config(codec, AD1988_MODEL_LAST, | 2982 | board_config = snd_hda_check_board_config(codec, AD1988_MODEL_LAST, |
2983 | ad1988_models, ad1988_cfg_tbl); | 2983 | ad1988_models, ad1988_cfg_tbl); |
2984 | if (board_config < 0) { | 2984 | if (board_config < 0) { |
2985 | printk(KERN_INFO "hda_codec: Unknown model for AD1988, trying auto-probe from BIOS...\n"); | 2985 | printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", |
2986 | codec->chip_name); | ||
2986 | board_config = AD1988_AUTO; | 2987 | board_config = AD1988_AUTO; |
2987 | } | 2988 | } |
2988 | 2989 | ||
@@ -3702,19 +3703,29 @@ static struct hda_amp_list ad1884a_loopbacks[] = { | |||
3702 | * Port F: Internal speakers | 3703 | * Port F: Internal speakers |
3703 | */ | 3704 | */ |
3704 | 3705 | ||
3705 | static struct hda_input_mux ad1884a_laptop_capture_source = { | 3706 | static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol, |
3706 | .num_items = 4, | 3707 | struct snd_ctl_elem_value *ucontrol) |
3707 | .items = { | 3708 | { |
3708 | { "Mic", 0x0 }, /* port-B */ | 3709 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
3709 | { "Internal Mic", 0x1 }, /* port-C */ | 3710 | int ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); |
3710 | { "Dock Mic", 0x4 }, /* port-E */ | 3711 | int mute = (!ucontrol->value.integer.value[0] && |
3711 | { "Mix", 0x3 }, | 3712 | !ucontrol->value.integer.value[1]); |
3712 | }, | 3713 | /* toggle GPIO1 according to the mute state */ |
3713 | }; | 3714 | snd_hda_codec_write_cache(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, |
3715 | mute ? 0x02 : 0x0); | ||
3716 | return ret; | ||
3717 | } | ||
3714 | 3718 | ||
3715 | static struct snd_kcontrol_new ad1884a_laptop_mixers[] = { | 3719 | static struct snd_kcontrol_new ad1884a_laptop_mixers[] = { |
3716 | HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), | 3720 | HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), |
3717 | HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT), | 3721 | { |
3722 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3723 | .name = "Master Playback Switch", | ||
3724 | .info = snd_hda_mixer_amp_switch_info, | ||
3725 | .get = snd_hda_mixer_amp_switch_get, | ||
3726 | .put = ad1884a_mobile_master_sw_put, | ||
3727 | .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), | ||
3728 | }, | ||
3718 | HDA_CODEC_MUTE("Dock Playback Switch", 0x12, 0x0, HDA_OUTPUT), | 3729 | HDA_CODEC_MUTE("Dock Playback Switch", 0x12, 0x0, HDA_OUTPUT), |
3719 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), | 3730 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), |
3720 | HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), | 3731 | HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), |
@@ -3729,36 +3740,9 @@ static struct snd_kcontrol_new ad1884a_laptop_mixers[] = { | |||
3729 | HDA_CODEC_VOLUME("Dock Mic Boost", 0x25, 0x0, HDA_OUTPUT), | 3740 | HDA_CODEC_VOLUME("Dock Mic Boost", 0x25, 0x0, HDA_OUTPUT), |
3730 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | 3741 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), |
3731 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | 3742 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), |
3732 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
3733 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
3734 | { | ||
3735 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3736 | /* The multiple "Capture Source" controls confuse alsamixer | ||
3737 | * So call somewhat different.. | ||
3738 | */ | ||
3739 | /* .name = "Capture Source", */ | ||
3740 | .name = "Input Source", | ||
3741 | .count = 2, | ||
3742 | .info = ad198x_mux_enum_info, | ||
3743 | .get = ad198x_mux_enum_get, | ||
3744 | .put = ad198x_mux_enum_put, | ||
3745 | }, | ||
3746 | { } /* end */ | 3743 | { } /* end */ |
3747 | }; | 3744 | }; |
3748 | 3745 | ||
3749 | static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol, | ||
3750 | struct snd_ctl_elem_value *ucontrol) | ||
3751 | { | ||
3752 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
3753 | int ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); | ||
3754 | int mute = (!ucontrol->value.integer.value[0] && | ||
3755 | !ucontrol->value.integer.value[1]); | ||
3756 | /* toggle GPIO1 according to the mute state */ | ||
3757 | snd_hda_codec_write_cache(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, | ||
3758 | mute ? 0x02 : 0x0); | ||
3759 | return ret; | ||
3760 | } | ||
3761 | |||
3762 | static struct snd_kcontrol_new ad1884a_mobile_mixers[] = { | 3746 | static struct snd_kcontrol_new ad1884a_mobile_mixers[] = { |
3763 | HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), | 3747 | HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), |
3764 | /*HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/ | 3748 | /*HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/ |
@@ -3828,6 +3812,63 @@ static int ad1884a_hp_init(struct hda_codec *codec) | |||
3828 | return 0; | 3812 | return 0; |
3829 | } | 3813 | } |
3830 | 3814 | ||
3815 | /* mute internal speaker if HP or docking HP is plugged */ | ||
3816 | static void ad1884a_laptop_automute(struct hda_codec *codec) | ||
3817 | { | ||
3818 | unsigned int present; | ||
3819 | |||
3820 | present = snd_hda_codec_read(codec, 0x11, 0, AC_VERB_GET_PIN_SENSE, 0); | ||
3821 | present &= AC_PINSENSE_PRESENCE; | ||
3822 | if (!present) { | ||
3823 | present = snd_hda_codec_read(codec, 0x12, 0, | ||
3824 | AC_VERB_GET_PIN_SENSE, 0); | ||
3825 | present &= AC_PINSENSE_PRESENCE; | ||
3826 | } | ||
3827 | snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, | ||
3828 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
3829 | snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE, | ||
3830 | present ? 0x00 : 0x02); | ||
3831 | } | ||
3832 | |||
3833 | /* switch to external mic if plugged */ | ||
3834 | static void ad1884a_laptop_automic(struct hda_codec *codec) | ||
3835 | { | ||
3836 | unsigned int idx; | ||
3837 | |||
3838 | if (snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) & | ||
3839 | AC_PINSENSE_PRESENCE) | ||
3840 | idx = 0; | ||
3841 | else if (snd_hda_codec_read(codec, 0x1c, 0, AC_VERB_GET_PIN_SENSE, 0) & | ||
3842 | AC_PINSENSE_PRESENCE) | ||
3843 | idx = 4; | ||
3844 | else | ||
3845 | idx = 1; | ||
3846 | snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL, idx); | ||
3847 | } | ||
3848 | |||
3849 | /* unsolicited event for HP jack sensing */ | ||
3850 | static void ad1884a_laptop_unsol_event(struct hda_codec *codec, | ||
3851 | unsigned int res) | ||
3852 | { | ||
3853 | switch (res >> 26) { | ||
3854 | case AD1884A_HP_EVENT: | ||
3855 | ad1884a_laptop_automute(codec); | ||
3856 | break; | ||
3857 | case AD1884A_MIC_EVENT: | ||
3858 | ad1884a_laptop_automic(codec); | ||
3859 | break; | ||
3860 | } | ||
3861 | } | ||
3862 | |||
3863 | /* initialize jack-sensing, too */ | ||
3864 | static int ad1884a_laptop_init(struct hda_codec *codec) | ||
3865 | { | ||
3866 | ad198x_init(codec); | ||
3867 | ad1884a_laptop_automute(codec); | ||
3868 | ad1884a_laptop_automic(codec); | ||
3869 | return 0; | ||
3870 | } | ||
3871 | |||
3831 | /* additional verbs for laptop model */ | 3872 | /* additional verbs for laptop model */ |
3832 | static struct hda_verb ad1884a_laptop_verbs[] = { | 3873 | static struct hda_verb ad1884a_laptop_verbs[] = { |
3833 | /* Port-A (HP) pin - always unmuted */ | 3874 | /* Port-A (HP) pin - always unmuted */ |
@@ -3844,11 +3885,19 @@ static struct hda_verb ad1884a_laptop_verbs[] = { | |||
3844 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | 3885 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, |
3845 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ | 3886 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ |
3846 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ | 3887 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ |
3888 | /* Port-D (docking line-out) pin - default unmuted */ | ||
3889 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
3847 | /* analog mix */ | 3890 | /* analog mix */ |
3848 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | 3891 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, |
3849 | /* unsolicited event for pin-sense */ | 3892 | /* unsolicited event for pin-sense */ |
3850 | {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, | 3893 | {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, |
3894 | {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, | ||
3851 | {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT}, | 3895 | {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT}, |
3896 | {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT}, | ||
3897 | /* allow to touch GPIO1 (for mute control) */ | ||
3898 | {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, | ||
3899 | {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, | ||
3900 | {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */ | ||
3852 | { } /* end */ | 3901 | { } /* end */ |
3853 | }; | 3902 | }; |
3854 | 3903 | ||
@@ -4008,6 +4057,7 @@ static struct snd_pci_quirk ad1884a_cfg_tbl[] = { | |||
4008 | SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30d0, "HP laptop", AD1884A_LAPTOP), | 4057 | SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30d0, "HP laptop", AD1884A_LAPTOP), |
4009 | SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30e0, "HP laptop", AD1884A_LAPTOP), | 4058 | SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30e0, "HP laptop", AD1884A_LAPTOP), |
4010 | SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3600, "HP laptop", AD1884A_LAPTOP), | 4059 | SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3600, "HP laptop", AD1884A_LAPTOP), |
4060 | SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x7010, "HP laptop", AD1884A_MOBILE), | ||
4011 | SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD), | 4061 | SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD), |
4012 | {} | 4062 | {} |
4013 | }; | 4063 | }; |
@@ -4057,9 +4107,8 @@ static int patch_ad1884a(struct hda_codec *codec) | |||
4057 | spec->mixers[0] = ad1884a_laptop_mixers; | 4107 | spec->mixers[0] = ad1884a_laptop_mixers; |
4058 | spec->init_verbs[spec->num_init_verbs++] = ad1884a_laptop_verbs; | 4108 | spec->init_verbs[spec->num_init_verbs++] = ad1884a_laptop_verbs; |
4059 | spec->multiout.dig_out_nid = 0; | 4109 | spec->multiout.dig_out_nid = 0; |
4060 | spec->input_mux = &ad1884a_laptop_capture_source; | 4110 | codec->patch_ops.unsol_event = ad1884a_laptop_unsol_event; |
4061 | codec->patch_ops.unsol_event = ad1884a_hp_unsol_event; | 4111 | codec->patch_ops.init = ad1884a_laptop_init; |
4062 | codec->patch_ops.init = ad1884a_hp_init; | ||
4063 | /* set the upper-limit for mixer amp to 0dB for avoiding the | 4112 | /* set the upper-limit for mixer amp to 0dB for avoiding the |
4064 | * possible damage by overloading | 4113 | * possible damage by overloading |
4065 | */ | 4114 | */ |