diff options
author | Takashi Iwai <tiwai@suse.de> | 2013-07-04 09:36:56 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2013-07-04 09:36:56 -0400 |
commit | 5ccc618fee67f0f0b2122dd4b32a02fd2b6a1569 (patch) | |
tree | 4b0399154707df80db62e25035cc87e06c951030 /sound/pci/hda/patch_analog.c | |
parent | aa95d61b43e0fcb0b2ce68e5efa37174fd9e5cd3 (diff) |
ALSA: hda - Remove static quirks for AD1884/1984 & variants
Since the necessary device-specific fixups for Thinkpad and HP devices
have been already ported, we can remove all static quirks for AD1884,
AD1984, AD1884A and AD1984A codecs.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda/patch_analog.c')
-rw-r--r-- | sound/pci/hda/patch_analog.c | 1348 |
1 files changed, 18 insertions, 1330 deletions
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 876d836ef742..bfa8f532841d 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c | |||
@@ -3423,167 +3423,19 @@ static int patch_ad1988(struct hda_codec *codec) | |||
3423 | * | 3423 | * |
3424 | * AD1984 = AD1884 + two digital mic-ins | 3424 | * AD1984 = AD1884 + two digital mic-ins |
3425 | * | 3425 | * |
3426 | * FIXME: | 3426 | * AD1883 / AD1884A / AD1984A / AD1984B |
3427 | * For simplicity, we share the single DAC for both HP and line-outs | 3427 | * |
3428 | * right now. The inidividual playbacks could be easily implemented, | 3428 | * port-B (0x14) - front mic-in |
3429 | * but no build-up framework is given, so far. | 3429 | * port-E (0x1c) - rear mic-in |
3430 | */ | 3430 | * port-F (0x16) - CD / ext out |
3431 | 3431 | * port-C (0x15) - rear line-in | |
3432 | #ifdef ENABLE_AD_STATIC_QUIRKS | 3432 | * port-D (0x12) - rear line-out |
3433 | static const hda_nid_t ad1884_dac_nids[1] = { | 3433 | * port-A (0x11) - front hp-out |
3434 | 0x04, | 3434 | * |
3435 | }; | 3435 | * AD1984A = AD1884A + digital-mic |
3436 | 3436 | * AD1883 = equivalent with AD1984A | |
3437 | static const hda_nid_t ad1884_adc_nids[2] = { | 3437 | * AD1984B = AD1984A + extra SPDIF-out |
3438 | 0x08, 0x09, | ||
3439 | }; | ||
3440 | |||
3441 | static const hda_nid_t ad1884_capsrc_nids[2] = { | ||
3442 | 0x0c, 0x0d, | ||
3443 | }; | ||
3444 | |||
3445 | #define AD1884_SPDIF_OUT 0x02 | ||
3446 | |||
3447 | static const struct hda_input_mux ad1884_capture_source = { | ||
3448 | .num_items = 4, | ||
3449 | .items = { | ||
3450 | { "Front Mic", 0x0 }, | ||
3451 | { "Mic", 0x1 }, | ||
3452 | { "CD", 0x2 }, | ||
3453 | { "Mix", 0x3 }, | ||
3454 | }, | ||
3455 | }; | ||
3456 | |||
3457 | static const struct snd_kcontrol_new ad1884_base_mixers[] = { | ||
3458 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), | ||
3459 | /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */ | ||
3460 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), | ||
3461 | HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
3462 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT), | ||
3463 | HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT), | ||
3464 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT), | ||
3465 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), | ||
3466 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT), | ||
3467 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT), | ||
3468 | HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT), | ||
3469 | HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT), | ||
3470 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x15, 0x0, HDA_INPUT), | ||
3471 | HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT), | ||
3472 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
3473 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
3474 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
3475 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
3476 | { | ||
3477 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3478 | /* The multiple "Capture Source" controls confuse alsamixer | ||
3479 | * So call somewhat different.. | ||
3480 | */ | ||
3481 | /* .name = "Capture Source", */ | ||
3482 | .name = "Input Source", | ||
3483 | .count = 2, | ||
3484 | .info = ad198x_mux_enum_info, | ||
3485 | .get = ad198x_mux_enum_get, | ||
3486 | .put = ad198x_mux_enum_put, | ||
3487 | }, | ||
3488 | /* SPDIF controls */ | ||
3489 | HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | ||
3490 | { | ||
3491 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3492 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", | ||
3493 | /* identical with ad1983 */ | ||
3494 | .info = ad1983_spdif_route_info, | ||
3495 | .get = ad1983_spdif_route_get, | ||
3496 | .put = ad1983_spdif_route_put, | ||
3497 | }, | ||
3498 | { } /* end */ | ||
3499 | }; | ||
3500 | |||
3501 | static const struct snd_kcontrol_new ad1984_dmic_mixers[] = { | ||
3502 | HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x05, 0x0, HDA_INPUT), | ||
3503 | HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x05, 0x0, HDA_INPUT), | ||
3504 | HDA_CODEC_VOLUME_IDX("Digital Mic Capture Volume", 1, 0x06, 0x0, | ||
3505 | HDA_INPUT), | ||
3506 | HDA_CODEC_MUTE_IDX("Digital Mic Capture Switch", 1, 0x06, 0x0, | ||
3507 | HDA_INPUT), | ||
3508 | { } /* end */ | ||
3509 | }; | ||
3510 | |||
3511 | /* | ||
3512 | * initialization verbs | ||
3513 | */ | 3438 | */ |
3514 | static const struct hda_verb ad1884_init_verbs[] = { | ||
3515 | /* DACs; mute as default */ | ||
3516 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
3517 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
3518 | /* Port-A (HP) mixer */ | ||
3519 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3520 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
3521 | /* Port-A pin */ | ||
3522 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
3523 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
3524 | /* HP selector - select DAC2 */ | ||
3525 | {0x22, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
3526 | /* Port-D (Line-out) mixer */ | ||
3527 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3528 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
3529 | /* Port-D pin */ | ||
3530 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
3531 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
3532 | /* Mono-out mixer */ | ||
3533 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3534 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
3535 | /* Mono-out pin */ | ||
3536 | {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
3537 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
3538 | /* Mono selector */ | ||
3539 | {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
3540 | /* Port-B (front mic) pin */ | ||
3541 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
3542 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3543 | /* Port-C (rear mic) pin */ | ||
3544 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
3545 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3546 | /* Analog mixer; mute as default */ | ||
3547 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
3548 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
3549 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
3550 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
3551 | /* Analog Mix output amp */ | ||
3552 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */ | ||
3553 | /* SPDIF output selector */ | ||
3554 | {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */ | ||
3555 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ | ||
3556 | { } /* end */ | ||
3557 | }; | ||
3558 | |||
3559 | #ifdef CONFIG_PM | ||
3560 | static const struct hda_amp_list ad1884_loopbacks[] = { | ||
3561 | { 0x20, HDA_INPUT, 0 }, /* Front Mic */ | ||
3562 | { 0x20, HDA_INPUT, 1 }, /* Mic */ | ||
3563 | { 0x20, HDA_INPUT, 2 }, /* CD */ | ||
3564 | { 0x20, HDA_INPUT, 4 }, /* Docking */ | ||
3565 | { } /* end */ | ||
3566 | }; | ||
3567 | #endif | ||
3568 | |||
3569 | static const char * const ad1884_slave_vols[] = { | ||
3570 | "PCM", "Mic", "Mono", "Front Mic", "Mic", "CD", | ||
3571 | "Internal Mic", "Dock Mic", /* "Beep", */ "IEC958", | ||
3572 | NULL | ||
3573 | }; | ||
3574 | |||
3575 | enum { | ||
3576 | AD1884_AUTO, | ||
3577 | AD1884_BASIC, | ||
3578 | AD1884_MODELS | ||
3579 | }; | ||
3580 | |||
3581 | static const char * const ad1884_models[AD1884_MODELS] = { | ||
3582 | [AD1884_AUTO] = "auto", | ||
3583 | [AD1884_BASIC] = "basic", | ||
3584 | }; | ||
3585 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
3586 | |||
3587 | 3439 | ||
3588 | /* set the upper-limit for mixer amp to 0dB for avoiding the possible | 3440 | /* set the upper-limit for mixer amp to 0dB for avoiding the possible |
3589 | * damage by overloading | 3441 | * damage by overloading |
@@ -3682,7 +3534,7 @@ static const struct snd_pci_quirk ad1884_fixup_tbl[] = { | |||
3682 | }; | 3534 | }; |
3683 | 3535 | ||
3684 | 3536 | ||
3685 | static int ad1884_parse_auto_config(struct hda_codec *codec) | 3537 | static int patch_ad1884(struct hda_codec *codec) |
3686 | { | 3538 | { |
3687 | struct ad198x_spec *spec; | 3539 | struct ad198x_spec *spec; |
3688 | int err; | 3540 | int err; |
@@ -3715,1170 +3567,6 @@ static int ad1884_parse_auto_config(struct hda_codec *codec) | |||
3715 | return err; | 3567 | return err; |
3716 | } | 3568 | } |
3717 | 3569 | ||
3718 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
3719 | static int patch_ad1884_basic(struct hda_codec *codec) | ||
3720 | { | ||
3721 | struct ad198x_spec *spec; | ||
3722 | int err; | ||
3723 | |||
3724 | err = alloc_ad_spec(codec); | ||
3725 | if (err < 0) | ||
3726 | return err; | ||
3727 | spec = codec->spec; | ||
3728 | |||
3729 | err = snd_hda_attach_beep_device(codec, 0x10); | ||
3730 | if (err < 0) { | ||
3731 | ad198x_free(codec); | ||
3732 | return err; | ||
3733 | } | ||
3734 | set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); | ||
3735 | |||
3736 | spec->multiout.max_channels = 2; | ||
3737 | spec->multiout.num_dacs = ARRAY_SIZE(ad1884_dac_nids); | ||
3738 | spec->multiout.dac_nids = ad1884_dac_nids; | ||
3739 | spec->multiout.dig_out_nid = AD1884_SPDIF_OUT; | ||
3740 | spec->num_adc_nids = ARRAY_SIZE(ad1884_adc_nids); | ||
3741 | spec->adc_nids = ad1884_adc_nids; | ||
3742 | spec->capsrc_nids = ad1884_capsrc_nids; | ||
3743 | spec->input_mux = &ad1884_capture_source; | ||
3744 | spec->num_mixers = 1; | ||
3745 | spec->mixers[0] = ad1884_base_mixers; | ||
3746 | spec->num_init_verbs = 1; | ||
3747 | spec->init_verbs[0] = ad1884_init_verbs; | ||
3748 | spec->spdif_route = 0; | ||
3749 | #ifdef CONFIG_PM | ||
3750 | spec->loopback.amplist = ad1884_loopbacks; | ||
3751 | #endif | ||
3752 | spec->vmaster_nid = 0x04; | ||
3753 | /* we need to cover all playback volumes */ | ||
3754 | spec->slave_vols = ad1884_slave_vols; | ||
3755 | /* slaves may contain input volumes, so we can't raise to 0dB blindly */ | ||
3756 | spec->avoid_init_slave_vol = 1; | ||
3757 | |||
3758 | codec->patch_ops = ad198x_patch_ops; | ||
3759 | |||
3760 | codec->no_trigger_sense = 1; | ||
3761 | codec->no_sticky_stream = 1; | ||
3762 | |||
3763 | return 0; | ||
3764 | } | ||
3765 | |||
3766 | static int patch_ad1884(struct hda_codec *codec) | ||
3767 | { | ||
3768 | int board_config; | ||
3769 | |||
3770 | board_config = snd_hda_check_board_config(codec, AD1884_MODELS, | ||
3771 | ad1884_models, NULL); | ||
3772 | if (board_config < 0) { | ||
3773 | printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", | ||
3774 | codec->chip_name); | ||
3775 | board_config = AD1884_AUTO; | ||
3776 | } | ||
3777 | |||
3778 | if (board_config == AD1884_AUTO) | ||
3779 | return ad1884_parse_auto_config(codec); | ||
3780 | else | ||
3781 | return patch_ad1884_basic(codec); | ||
3782 | } | ||
3783 | #else /* ENABLE_AD_STATIC_QUIRKS */ | ||
3784 | #define patch_ad1884 ad1884_parse_auto_config | ||
3785 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
3786 | |||
3787 | |||
3788 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
3789 | /* | ||
3790 | * Lenovo Thinkpad T61/X61 | ||
3791 | */ | ||
3792 | static const struct hda_input_mux ad1984_thinkpad_capture_source = { | ||
3793 | .num_items = 4, | ||
3794 | .items = { | ||
3795 | { "Mic", 0x0 }, | ||
3796 | { "Internal Mic", 0x1 }, | ||
3797 | { "Mix", 0x3 }, | ||
3798 | { "Dock Mic", 0x4 }, | ||
3799 | }, | ||
3800 | }; | ||
3801 | |||
3802 | |||
3803 | /* | ||
3804 | * Dell Precision T3400 | ||
3805 | */ | ||
3806 | static const struct hda_input_mux ad1984_dell_desktop_capture_source = { | ||
3807 | .num_items = 3, | ||
3808 | .items = { | ||
3809 | { "Front Mic", 0x0 }, | ||
3810 | { "Line-In", 0x1 }, | ||
3811 | { "Mix", 0x3 }, | ||
3812 | }, | ||
3813 | }; | ||
3814 | |||
3815 | |||
3816 | static const struct snd_kcontrol_new ad1984_thinkpad_mixers[] = { | ||
3817 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), | ||
3818 | /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */ | ||
3819 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), | ||
3820 | HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
3821 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT), | ||
3822 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT), | ||
3823 | HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT), | ||
3824 | HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT), | ||
3825 | HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT), | ||
3826 | HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT), | ||
3827 | HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT), | ||
3828 | HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT), | ||
3829 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT), | ||
3830 | HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT), | ||
3831 | HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT), | ||
3832 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
3833 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
3834 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
3835 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
3836 | { | ||
3837 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3838 | /* The multiple "Capture Source" controls confuse alsamixer | ||
3839 | * So call somewhat different.. | ||
3840 | */ | ||
3841 | /* .name = "Capture Source", */ | ||
3842 | .name = "Input Source", | ||
3843 | .count = 2, | ||
3844 | .info = ad198x_mux_enum_info, | ||
3845 | .get = ad198x_mux_enum_get, | ||
3846 | .put = ad198x_mux_enum_put, | ||
3847 | }, | ||
3848 | /* SPDIF controls */ | ||
3849 | HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | ||
3850 | { | ||
3851 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3852 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", | ||
3853 | /* identical with ad1983 */ | ||
3854 | .info = ad1983_spdif_route_info, | ||
3855 | .get = ad1983_spdif_route_get, | ||
3856 | .put = ad1983_spdif_route_put, | ||
3857 | }, | ||
3858 | { } /* end */ | ||
3859 | }; | ||
3860 | |||
3861 | /* additional verbs */ | ||
3862 | static const struct hda_verb ad1984_thinkpad_init_verbs[] = { | ||
3863 | /* Port-E (docking station mic) pin */ | ||
3864 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
3865 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
3866 | /* docking mic boost */ | ||
3867 | {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
3868 | /* Analog PC Beeper - allow firmware/ACPI beeps */ | ||
3869 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3) | 0x1a}, | ||
3870 | /* Analog mixer - docking mic; mute as default */ | ||
3871 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
3872 | /* enable EAPD bit */ | ||
3873 | {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, | ||
3874 | { } /* end */ | ||
3875 | }; | ||
3876 | |||
3877 | /* | ||
3878 | * Dell Precision T3400 | ||
3879 | */ | ||
3880 | static const struct snd_kcontrol_new ad1984_dell_desktop_mixers[] = { | ||
3881 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), | ||
3882 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), | ||
3883 | HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
3884 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT), | ||
3885 | HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT), | ||
3886 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT), | ||
3887 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), | ||
3888 | HDA_CODEC_VOLUME("Line-In Playback Volume", 0x20, 0x01, HDA_INPUT), | ||
3889 | HDA_CODEC_MUTE("Line-In Playback Switch", 0x20, 0x01, HDA_INPUT), | ||
3890 | HDA_CODEC_VOLUME("Line-In Boost Volume", 0x15, 0x0, HDA_INPUT), | ||
3891 | HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT), | ||
3892 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
3893 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
3894 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
3895 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
3896 | { | ||
3897 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3898 | /* The multiple "Capture Source" controls confuse alsamixer | ||
3899 | * So call somewhat different.. | ||
3900 | */ | ||
3901 | /* .name = "Capture Source", */ | ||
3902 | .name = "Input Source", | ||
3903 | .count = 2, | ||
3904 | .info = ad198x_mux_enum_info, | ||
3905 | .get = ad198x_mux_enum_get, | ||
3906 | .put = ad198x_mux_enum_put, | ||
3907 | }, | ||
3908 | { } /* end */ | ||
3909 | }; | ||
3910 | |||
3911 | /* Digial MIC ADC NID 0x05 + 0x06 */ | ||
3912 | static int ad1984_pcm_dmic_prepare(struct hda_pcm_stream *hinfo, | ||
3913 | struct hda_codec *codec, | ||
3914 | unsigned int stream_tag, | ||
3915 | unsigned int format, | ||
3916 | struct snd_pcm_substream *substream) | ||
3917 | { | ||
3918 | snd_hda_codec_setup_stream(codec, 0x05 + substream->number, | ||
3919 | stream_tag, 0, format); | ||
3920 | return 0; | ||
3921 | } | ||
3922 | |||
3923 | static int ad1984_pcm_dmic_cleanup(struct hda_pcm_stream *hinfo, | ||
3924 | struct hda_codec *codec, | ||
3925 | struct snd_pcm_substream *substream) | ||
3926 | { | ||
3927 | snd_hda_codec_cleanup_stream(codec, 0x05 + substream->number); | ||
3928 | return 0; | ||
3929 | } | ||
3930 | |||
3931 | static const struct hda_pcm_stream ad1984_pcm_dmic_capture = { | ||
3932 | .substreams = 2, | ||
3933 | .channels_min = 2, | ||
3934 | .channels_max = 2, | ||
3935 | .nid = 0x05, | ||
3936 | .ops = { | ||
3937 | .prepare = ad1984_pcm_dmic_prepare, | ||
3938 | .cleanup = ad1984_pcm_dmic_cleanup | ||
3939 | }, | ||
3940 | }; | ||
3941 | |||
3942 | static int ad1984_build_pcms(struct hda_codec *codec) | ||
3943 | { | ||
3944 | struct ad198x_spec *spec = codec->spec; | ||
3945 | struct hda_pcm *info; | ||
3946 | int err; | ||
3947 | |||
3948 | err = ad198x_build_pcms(codec); | ||
3949 | if (err < 0) | ||
3950 | return err; | ||
3951 | |||
3952 | info = spec->pcm_rec + codec->num_pcms; | ||
3953 | codec->num_pcms++; | ||
3954 | info->name = "AD1984 Digital Mic"; | ||
3955 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad1984_pcm_dmic_capture; | ||
3956 | return 0; | ||
3957 | } | ||
3958 | |||
3959 | /* models */ | ||
3960 | enum { | ||
3961 | AD1984_AUTO, | ||
3962 | AD1984_BASIC, | ||
3963 | AD1984_THINKPAD, | ||
3964 | AD1984_DELL_DESKTOP, | ||
3965 | AD1984_MODELS | ||
3966 | }; | ||
3967 | |||
3968 | static const char * const ad1984_models[AD1984_MODELS] = { | ||
3969 | [AD1984_AUTO] = "auto", | ||
3970 | [AD1984_BASIC] = "basic", | ||
3971 | [AD1984_THINKPAD] = "thinkpad", | ||
3972 | [AD1984_DELL_DESKTOP] = "dell_desktop", | ||
3973 | }; | ||
3974 | |||
3975 | static const struct snd_pci_quirk ad1984_cfg_tbl[] = { | ||
3976 | /* Lenovo Thinkpad T61/X61 */ | ||
3977 | SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1984_THINKPAD), | ||
3978 | SND_PCI_QUIRK(0x1028, 0x0214, "Dell T3400", AD1984_DELL_DESKTOP), | ||
3979 | SND_PCI_QUIRK(0x1028, 0x0233, "Dell Latitude E6400", AD1984_DELL_DESKTOP), | ||
3980 | {} | ||
3981 | }; | ||
3982 | |||
3983 | static int patch_ad1984(struct hda_codec *codec) | ||
3984 | { | ||
3985 | struct ad198x_spec *spec; | ||
3986 | int board_config, err; | ||
3987 | |||
3988 | board_config = snd_hda_check_board_config(codec, AD1984_MODELS, | ||
3989 | ad1984_models, ad1984_cfg_tbl); | ||
3990 | if (board_config < 0) { | ||
3991 | printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", | ||
3992 | codec->chip_name); | ||
3993 | board_config = AD1984_AUTO; | ||
3994 | } | ||
3995 | |||
3996 | if (board_config == AD1984_AUTO) | ||
3997 | return ad1884_parse_auto_config(codec); | ||
3998 | |||
3999 | err = patch_ad1884_basic(codec); | ||
4000 | if (err < 0) | ||
4001 | return err; | ||
4002 | spec = codec->spec; | ||
4003 | |||
4004 | switch (board_config) { | ||
4005 | case AD1984_BASIC: | ||
4006 | /* additional digital mics */ | ||
4007 | spec->mixers[spec->num_mixers++] = ad1984_dmic_mixers; | ||
4008 | codec->patch_ops.build_pcms = ad1984_build_pcms; | ||
4009 | break; | ||
4010 | case AD1984_THINKPAD: | ||
4011 | if (codec->subsystem_id == 0x17aa20fb) { | ||
4012 | /* Thinpad X300 does not have the ability to do SPDIF, | ||
4013 | or attach to docking station to use SPDIF */ | ||
4014 | spec->multiout.dig_out_nid = 0; | ||
4015 | } else | ||
4016 | spec->multiout.dig_out_nid = AD1884_SPDIF_OUT; | ||
4017 | spec->input_mux = &ad1984_thinkpad_capture_source; | ||
4018 | spec->mixers[0] = ad1984_thinkpad_mixers; | ||
4019 | spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs; | ||
4020 | spec->analog_beep = 1; | ||
4021 | break; | ||
4022 | case AD1984_DELL_DESKTOP: | ||
4023 | spec->multiout.dig_out_nid = 0; | ||
4024 | spec->input_mux = &ad1984_dell_desktop_capture_source; | ||
4025 | spec->mixers[0] = ad1984_dell_desktop_mixers; | ||
4026 | break; | ||
4027 | } | ||
4028 | return 0; | ||
4029 | } | ||
4030 | #else /* ENABLE_AD_STATIC_QUIRKS */ | ||
4031 | #define patch_ad1984 ad1884_parse_auto_config | ||
4032 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
4033 | |||
4034 | |||
4035 | /* | ||
4036 | * AD1883 / AD1884A / AD1984A / AD1984B | ||
4037 | * | ||
4038 | * port-B (0x14) - front mic-in | ||
4039 | * port-E (0x1c) - rear mic-in | ||
4040 | * port-F (0x16) - CD / ext out | ||
4041 | * port-C (0x15) - rear line-in | ||
4042 | * port-D (0x12) - rear line-out | ||
4043 | * port-A (0x11) - front hp-out | ||
4044 | * | ||
4045 | * AD1984A = AD1884A + digital-mic | ||
4046 | * AD1883 = equivalent with AD1984A | ||
4047 | * AD1984B = AD1984A + extra SPDIF-out | ||
4048 | * | ||
4049 | * FIXME: | ||
4050 | * We share the single DAC for both HP and line-outs (see AD1884/1984). | ||
4051 | */ | ||
4052 | |||
4053 | #ifdef ENABLE_AD_STATIC_QUIRKS | ||
4054 | static const hda_nid_t ad1884a_dac_nids[1] = { | ||
4055 | 0x03, | ||
4056 | }; | ||
4057 | |||
4058 | #define ad1884a_adc_nids ad1884_adc_nids | ||
4059 | #define ad1884a_capsrc_nids ad1884_capsrc_nids | ||
4060 | |||
4061 | #define AD1884A_SPDIF_OUT 0x02 | ||
4062 | |||
4063 | static const struct hda_input_mux ad1884a_capture_source = { | ||
4064 | .num_items = 5, | ||
4065 | .items = { | ||
4066 | { "Front Mic", 0x0 }, | ||
4067 | { "Mic", 0x4 }, | ||
4068 | { "Line", 0x1 }, | ||
4069 | { "CD", 0x2 }, | ||
4070 | { "Mix", 0x3 }, | ||
4071 | }, | ||
4072 | }; | ||
4073 | |||
4074 | static const struct snd_kcontrol_new ad1884a_base_mixers[] = { | ||
4075 | HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
4076 | HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
4077 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), | ||
4078 | HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
4079 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT), | ||
4080 | HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT), | ||
4081 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), | ||
4082 | HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), | ||
4083 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT), | ||
4084 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), | ||
4085 | HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT), | ||
4086 | HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT), | ||
4087 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT), | ||
4088 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT), | ||
4089 | HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT), | ||
4090 | HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT), | ||
4091 | HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT), | ||
4092 | HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x0, HDA_INPUT), | ||
4093 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT), | ||
4094 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
4095 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
4096 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
4097 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
4098 | { | ||
4099 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4100 | /* The multiple "Capture Source" controls confuse alsamixer | ||
4101 | * So call somewhat different.. | ||
4102 | */ | ||
4103 | /* .name = "Capture Source", */ | ||
4104 | .name = "Input Source", | ||
4105 | .count = 2, | ||
4106 | .info = ad198x_mux_enum_info, | ||
4107 | .get = ad198x_mux_enum_get, | ||
4108 | .put = ad198x_mux_enum_put, | ||
4109 | }, | ||
4110 | /* SPDIF controls */ | ||
4111 | HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | ||
4112 | { | ||
4113 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4114 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", | ||
4115 | /* identical with ad1983 */ | ||
4116 | .info = ad1983_spdif_route_info, | ||
4117 | .get = ad1983_spdif_route_get, | ||
4118 | .put = ad1983_spdif_route_put, | ||
4119 | }, | ||
4120 | { } /* end */ | ||
4121 | }; | ||
4122 | |||
4123 | /* | ||
4124 | * initialization verbs | ||
4125 | */ | ||
4126 | static const struct hda_verb ad1884a_init_verbs[] = { | ||
4127 | /* DACs; unmute as default */ | ||
4128 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ | ||
4129 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ | ||
4130 | /* Port-A (HP) mixer - route only from analog mixer */ | ||
4131 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4132 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4133 | /* Port-A pin */ | ||
4134 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
4135 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4136 | /* Port-D (Line-out) mixer - route only from analog mixer */ | ||
4137 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4138 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4139 | /* Port-D pin */ | ||
4140 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
4141 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4142 | /* Mono-out mixer - route only from analog mixer */ | ||
4143 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4144 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4145 | /* Mono-out pin */ | ||
4146 | {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
4147 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4148 | /* Port-B (front mic) pin */ | ||
4149 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
4150 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4151 | /* Port-C (rear line-in) pin */ | ||
4152 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
4153 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4154 | /* Port-E (rear mic) pin */ | ||
4155 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
4156 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4157 | {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* no boost */ | ||
4158 | /* Port-F (CD) pin */ | ||
4159 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
4160 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4161 | /* Analog mixer; mute as default */ | ||
4162 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4163 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
4164 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
4165 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
4166 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, /* aux */ | ||
4167 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, | ||
4168 | /* Analog Mix output amp */ | ||
4169 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4170 | /* capture sources */ | ||
4171 | {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
4172 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4173 | {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
4174 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4175 | /* SPDIF output amp */ | ||
4176 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ | ||
4177 | { } /* end */ | ||
4178 | }; | ||
4179 | |||
4180 | #ifdef CONFIG_PM | ||
4181 | static const struct hda_amp_list ad1884a_loopbacks[] = { | ||
4182 | { 0x20, HDA_INPUT, 0 }, /* Front Mic */ | ||
4183 | { 0x20, HDA_INPUT, 1 }, /* Mic */ | ||
4184 | { 0x20, HDA_INPUT, 2 }, /* CD */ | ||
4185 | { 0x20, HDA_INPUT, 4 }, /* Docking */ | ||
4186 | { } /* end */ | ||
4187 | }; | ||
4188 | #endif | ||
4189 | |||
4190 | /* | ||
4191 | * Laptop model | ||
4192 | * | ||
4193 | * Port A: Headphone jack | ||
4194 | * Port B: MIC jack | ||
4195 | * Port C: Internal MIC | ||
4196 | * Port D: Dock Line Out (if enabled) | ||
4197 | * Port E: Dock Line In (if enabled) | ||
4198 | * Port F: Internal speakers | ||
4199 | */ | ||
4200 | |||
4201 | static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol, | ||
4202 | struct snd_ctl_elem_value *ucontrol) | ||
4203 | { | ||
4204 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
4205 | int ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); | ||
4206 | int mute = (!ucontrol->value.integer.value[0] && | ||
4207 | !ucontrol->value.integer.value[1]); | ||
4208 | /* toggle GPIO1 according to the mute state */ | ||
4209 | snd_hda_codec_write_cache(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, | ||
4210 | mute ? 0x02 : 0x0); | ||
4211 | return ret; | ||
4212 | } | ||
4213 | |||
4214 | static const struct snd_kcontrol_new ad1884a_laptop_mixers[] = { | ||
4215 | HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
4216 | { | ||
4217 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4218 | .name = "Master Playback Switch", | ||
4219 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
4220 | .info = snd_hda_mixer_amp_switch_info, | ||
4221 | .get = snd_hda_mixer_amp_switch_get, | ||
4222 | .put = ad1884a_mobile_master_sw_put, | ||
4223 | .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), | ||
4224 | }, | ||
4225 | HDA_CODEC_MUTE("Dock Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
4226 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), | ||
4227 | HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), | ||
4228 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT), | ||
4229 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT), | ||
4230 | HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT), | ||
4231 | HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT), | ||
4232 | HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT), | ||
4233 | HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT), | ||
4234 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT), | ||
4235 | HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT), | ||
4236 | HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT), | ||
4237 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
4238 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
4239 | { } /* end */ | ||
4240 | }; | ||
4241 | |||
4242 | static const struct snd_kcontrol_new ad1884a_mobile_mixers[] = { | ||
4243 | HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
4244 | /*HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/ | ||
4245 | { | ||
4246 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4247 | .name = "Master Playback Switch", | ||
4248 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
4249 | .info = snd_hda_mixer_amp_switch_info, | ||
4250 | .get = snd_hda_mixer_amp_switch_get, | ||
4251 | .put = ad1884a_mobile_master_sw_put, | ||
4252 | .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), | ||
4253 | }, | ||
4254 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), | ||
4255 | HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), | ||
4256 | HDA_CODEC_VOLUME("Mic Capture Volume", 0x14, 0x0, HDA_INPUT), | ||
4257 | HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x15, 0x0, HDA_INPUT), | ||
4258 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
4259 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
4260 | { } /* end */ | ||
4261 | }; | ||
4262 | |||
4263 | /* mute internal speaker if HP is plugged */ | ||
4264 | static void ad1884a_hp_automute(struct hda_codec *codec) | ||
4265 | { | ||
4266 | unsigned int present; | ||
4267 | |||
4268 | present = snd_hda_jack_detect(codec, 0x11); | ||
4269 | snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, | ||
4270 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
4271 | snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE, | ||
4272 | present ? 0x00 : 0x02); | ||
4273 | } | ||
4274 | |||
4275 | /* switch to external mic if plugged */ | ||
4276 | static void ad1884a_hp_automic(struct hda_codec *codec) | ||
4277 | { | ||
4278 | unsigned int present; | ||
4279 | |||
4280 | present = snd_hda_jack_detect(codec, 0x14); | ||
4281 | snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL, | ||
4282 | present ? 0 : 1); | ||
4283 | } | ||
4284 | |||
4285 | #define AD1884A_HP_EVENT 0x37 | ||
4286 | #define AD1884A_MIC_EVENT 0x36 | ||
4287 | |||
4288 | /* unsolicited event for HP jack sensing */ | ||
4289 | static void ad1884a_hp_unsol_event(struct hda_codec *codec, unsigned int res) | ||
4290 | { | ||
4291 | switch (res >> 26) { | ||
4292 | case AD1884A_HP_EVENT: | ||
4293 | ad1884a_hp_automute(codec); | ||
4294 | break; | ||
4295 | case AD1884A_MIC_EVENT: | ||
4296 | ad1884a_hp_automic(codec); | ||
4297 | break; | ||
4298 | } | ||
4299 | } | ||
4300 | |||
4301 | /* initialize jack-sensing, too */ | ||
4302 | static int ad1884a_hp_init(struct hda_codec *codec) | ||
4303 | { | ||
4304 | ad198x_init(codec); | ||
4305 | ad1884a_hp_automute(codec); | ||
4306 | ad1884a_hp_automic(codec); | ||
4307 | return 0; | ||
4308 | } | ||
4309 | |||
4310 | /* mute internal speaker if HP or docking HP is plugged */ | ||
4311 | static void ad1884a_laptop_automute(struct hda_codec *codec) | ||
4312 | { | ||
4313 | unsigned int present; | ||
4314 | |||
4315 | present = snd_hda_jack_detect(codec, 0x11); | ||
4316 | if (!present) | ||
4317 | present = snd_hda_jack_detect(codec, 0x12); | ||
4318 | snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, | ||
4319 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
4320 | snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE, | ||
4321 | present ? 0x00 : 0x02); | ||
4322 | } | ||
4323 | |||
4324 | /* switch to external mic if plugged */ | ||
4325 | static void ad1884a_laptop_automic(struct hda_codec *codec) | ||
4326 | { | ||
4327 | unsigned int idx; | ||
4328 | |||
4329 | if (snd_hda_jack_detect(codec, 0x14)) | ||
4330 | idx = 0; | ||
4331 | else if (snd_hda_jack_detect(codec, 0x1c)) | ||
4332 | idx = 4; | ||
4333 | else | ||
4334 | idx = 1; | ||
4335 | snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL, idx); | ||
4336 | } | ||
4337 | |||
4338 | /* unsolicited event for HP jack sensing */ | ||
4339 | static void ad1884a_laptop_unsol_event(struct hda_codec *codec, | ||
4340 | unsigned int res) | ||
4341 | { | ||
4342 | switch (res >> 26) { | ||
4343 | case AD1884A_HP_EVENT: | ||
4344 | ad1884a_laptop_automute(codec); | ||
4345 | break; | ||
4346 | case AD1884A_MIC_EVENT: | ||
4347 | ad1884a_laptop_automic(codec); | ||
4348 | break; | ||
4349 | } | ||
4350 | } | ||
4351 | |||
4352 | /* initialize jack-sensing, too */ | ||
4353 | static int ad1884a_laptop_init(struct hda_codec *codec) | ||
4354 | { | ||
4355 | ad198x_init(codec); | ||
4356 | ad1884a_laptop_automute(codec); | ||
4357 | ad1884a_laptop_automic(codec); | ||
4358 | return 0; | ||
4359 | } | ||
4360 | |||
4361 | /* additional verbs for laptop model */ | ||
4362 | static const struct hda_verb ad1884a_laptop_verbs[] = { | ||
4363 | /* Port-A (HP) pin - always unmuted */ | ||
4364 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4365 | /* Port-F (int speaker) mixer - route only from analog mixer */ | ||
4366 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4367 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4368 | /* Port-F (int speaker) pin */ | ||
4369 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
4370 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4371 | /* required for compaq 6530s/6531s speaker output */ | ||
4372 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
4373 | /* Port-C pin - internal mic-in */ | ||
4374 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
4375 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ | ||
4376 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ | ||
4377 | /* Port-D (docking line-out) pin - default unmuted */ | ||
4378 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4379 | /* analog mix */ | ||
4380 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
4381 | /* unsolicited event for pin-sense */ | ||
4382 | {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, | ||
4383 | {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, | ||
4384 | {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT}, | ||
4385 | {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT}, | ||
4386 | /* allow to touch GPIO1 (for mute control) */ | ||
4387 | {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, | ||
4388 | {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, | ||
4389 | {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */ | ||
4390 | { } /* end */ | ||
4391 | }; | ||
4392 | |||
4393 | static const struct hda_verb ad1884a_mobile_verbs[] = { | ||
4394 | /* DACs; unmute as default */ | ||
4395 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ | ||
4396 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ | ||
4397 | /* Port-A (HP) mixer - route only from analog mixer */ | ||
4398 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4399 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4400 | /* Port-A pin */ | ||
4401 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
4402 | /* Port-A (HP) pin - always unmuted */ | ||
4403 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4404 | /* Port-B (mic jack) pin */ | ||
4405 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
4406 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ | ||
4407 | /* Port-C (int mic) pin */ | ||
4408 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
4409 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ | ||
4410 | /* Port-F (int speaker) mixer - route only from analog mixer */ | ||
4411 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4412 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4413 | /* Port-F pin */ | ||
4414 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
4415 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4416 | /* Analog mixer; mute as default */ | ||
4417 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4418 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
4419 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
4420 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
4421 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
4422 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, | ||
4423 | /* Analog Mix output amp */ | ||
4424 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4425 | /* capture sources */ | ||
4426 | /* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */ /* set via unsol */ | ||
4427 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4428 | {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
4429 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4430 | /* unsolicited event for pin-sense */ | ||
4431 | {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, | ||
4432 | {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT}, | ||
4433 | /* allow to touch GPIO1 (for mute control) */ | ||
4434 | {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, | ||
4435 | {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, | ||
4436 | {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */ | ||
4437 | { } /* end */ | ||
4438 | }; | ||
4439 | |||
4440 | /* | ||
4441 | * Thinkpad X300 | ||
4442 | * 0x11 - HP | ||
4443 | * 0x12 - speaker | ||
4444 | * 0x14 - mic-in | ||
4445 | * 0x17 - built-in mic | ||
4446 | */ | ||
4447 | |||
4448 | static const struct hda_verb ad1984a_thinkpad_verbs[] = { | ||
4449 | /* HP unmute */ | ||
4450 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4451 | /* analog mix */ | ||
4452 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
4453 | /* turn on EAPD */ | ||
4454 | {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, | ||
4455 | /* unsolicited event for pin-sense */ | ||
4456 | {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, | ||
4457 | /* internal mic - dmic */ | ||
4458 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
4459 | /* set magic COEFs for dmic */ | ||
4460 | {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7}, | ||
4461 | {0x01, AC_VERB_SET_PROC_COEF, 0x08}, | ||
4462 | { } /* end */ | ||
4463 | }; | ||
4464 | |||
4465 | static const struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = { | ||
4466 | HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
4467 | HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
4468 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), | ||
4469 | HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), | ||
4470 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT), | ||
4471 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT), | ||
4472 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT), | ||
4473 | HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x17, 0x0, HDA_INPUT), | ||
4474 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
4475 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
4476 | { | ||
4477 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4478 | .name = "Capture Source", | ||
4479 | .info = ad198x_mux_enum_info, | ||
4480 | .get = ad198x_mux_enum_get, | ||
4481 | .put = ad198x_mux_enum_put, | ||
4482 | }, | ||
4483 | { } /* end */ | ||
4484 | }; | ||
4485 | |||
4486 | static const struct hda_input_mux ad1984a_thinkpad_capture_source = { | ||
4487 | .num_items = 3, | ||
4488 | .items = { | ||
4489 | { "Mic", 0x0 }, | ||
4490 | { "Internal Mic", 0x5 }, | ||
4491 | { "Mix", 0x3 }, | ||
4492 | }, | ||
4493 | }; | ||
4494 | |||
4495 | /* mute internal speaker if HP is plugged */ | ||
4496 | static void ad1984a_thinkpad_automute(struct hda_codec *codec) | ||
4497 | { | ||
4498 | unsigned int present; | ||
4499 | |||
4500 | present = snd_hda_jack_detect(codec, 0x11); | ||
4501 | snd_hda_codec_amp_stereo(codec, 0x12, HDA_OUTPUT, 0, | ||
4502 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
4503 | } | ||
4504 | |||
4505 | /* unsolicited event for HP jack sensing */ | ||
4506 | static void ad1984a_thinkpad_unsol_event(struct hda_codec *codec, | ||
4507 | unsigned int res) | ||
4508 | { | ||
4509 | if ((res >> 26) != AD1884A_HP_EVENT) | ||
4510 | return; | ||
4511 | ad1984a_thinkpad_automute(codec); | ||
4512 | } | ||
4513 | |||
4514 | /* initialize jack-sensing, too */ | ||
4515 | static int ad1984a_thinkpad_init(struct hda_codec *codec) | ||
4516 | { | ||
4517 | ad198x_init(codec); | ||
4518 | ad1984a_thinkpad_automute(codec); | ||
4519 | return 0; | ||
4520 | } | ||
4521 | |||
4522 | /* | ||
4523 | * Precision R5500 | ||
4524 | * 0x12 - HP/line-out | ||
4525 | * 0x13 - speaker (mono) | ||
4526 | * 0x15 - mic-in | ||
4527 | */ | ||
4528 | |||
4529 | static const struct hda_verb ad1984a_precision_verbs[] = { | ||
4530 | /* Unmute main output path */ | ||
4531 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ | ||
4532 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE + 0x1f}, /* 0dB */ | ||
4533 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) + 0x17}, /* 0dB */ | ||
4534 | /* Analog mixer; mute as default */ | ||
4535 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4536 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
4537 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
4538 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
4539 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
4540 | /* Select mic as input */ | ||
4541 | {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
4542 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE + 0x27}, /* 0dB */ | ||
4543 | /* Configure as mic */ | ||
4544 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
4545 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ | ||
4546 | /* HP unmute */ | ||
4547 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4548 | /* turn on EAPD */ | ||
4549 | {0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, | ||
4550 | /* unsolicited event for pin-sense */ | ||
4551 | {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, | ||
4552 | { } /* end */ | ||
4553 | }; | ||
4554 | |||
4555 | static const struct snd_kcontrol_new ad1984a_precision_mixers[] = { | ||
4556 | HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
4557 | HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
4558 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), | ||
4559 | HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), | ||
4560 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT), | ||
4561 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT), | ||
4562 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x15, 0x0, HDA_INPUT), | ||
4563 | HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
4564 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x13, 0x0, HDA_OUTPUT), | ||
4565 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
4566 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
4567 | { } /* end */ | ||
4568 | }; | ||
4569 | |||
4570 | |||
4571 | /* mute internal speaker if HP is plugged */ | ||
4572 | static void ad1984a_precision_automute(struct hda_codec *codec) | ||
4573 | { | ||
4574 | unsigned int present; | ||
4575 | |||
4576 | present = snd_hda_jack_detect(codec, 0x12); | ||
4577 | snd_hda_codec_amp_stereo(codec, 0x13, HDA_OUTPUT, 0, | ||
4578 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
4579 | } | ||
4580 | |||
4581 | |||
4582 | /* unsolicited event for HP jack sensing */ | ||
4583 | static void ad1984a_precision_unsol_event(struct hda_codec *codec, | ||
4584 | unsigned int res) | ||
4585 | { | ||
4586 | if ((res >> 26) != AD1884A_HP_EVENT) | ||
4587 | return; | ||
4588 | ad1984a_precision_automute(codec); | ||
4589 | } | ||
4590 | |||
4591 | /* initialize jack-sensing, too */ | ||
4592 | static int ad1984a_precision_init(struct hda_codec *codec) | ||
4593 | { | ||
4594 | ad198x_init(codec); | ||
4595 | ad1984a_precision_automute(codec); | ||
4596 | return 0; | ||
4597 | } | ||
4598 | |||
4599 | |||
4600 | /* | ||
4601 | * HP Touchsmart | ||
4602 | * port-A (0x11) - front hp-out | ||
4603 | * port-B (0x14) - unused | ||
4604 | * port-C (0x15) - unused | ||
4605 | * port-D (0x12) - rear line out | ||
4606 | * port-E (0x1c) - front mic-in | ||
4607 | * port-F (0x16) - Internal speakers | ||
4608 | * digital-mic (0x17) - Internal mic | ||
4609 | */ | ||
4610 | |||
4611 | static const struct hda_verb ad1984a_touchsmart_verbs[] = { | ||
4612 | /* DACs; unmute as default */ | ||
4613 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ | ||
4614 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ | ||
4615 | /* Port-A (HP) mixer - route only from analog mixer */ | ||
4616 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4617 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4618 | /* Port-A pin */ | ||
4619 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
4620 | /* Port-A (HP) pin - always unmuted */ | ||
4621 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4622 | /* Port-E (int speaker) mixer - route only from analog mixer */ | ||
4623 | {0x25, AC_VERB_SET_AMP_GAIN_MUTE, 0x03}, | ||
4624 | /* Port-E pin */ | ||
4625 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
4626 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4627 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
4628 | /* Port-F (int speaker) mixer - route only from analog mixer */ | ||
4629 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4630 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4631 | /* Port-F pin */ | ||
4632 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
4633 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4634 | /* Analog mixer; mute as default */ | ||
4635 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4636 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
4637 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
4638 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
4639 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
4640 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, | ||
4641 | /* Analog Mix output amp */ | ||
4642 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4643 | /* capture sources */ | ||
4644 | /* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */ /* set via unsol */ | ||
4645 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4646 | {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
4647 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4648 | /* unsolicited event for pin-sense */ | ||
4649 | {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, | ||
4650 | {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT}, | ||
4651 | /* allow to touch GPIO1 (for mute control) */ | ||
4652 | {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, | ||
4653 | {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, | ||
4654 | {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */ | ||
4655 | /* internal mic - dmic */ | ||
4656 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
4657 | /* set magic COEFs for dmic */ | ||
4658 | {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7}, | ||
4659 | {0x01, AC_VERB_SET_PROC_COEF, 0x08}, | ||
4660 | { } /* end */ | ||
4661 | }; | ||
4662 | |||
4663 | static const struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = { | ||
4664 | HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
4665 | /* HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/ | ||
4666 | { | ||
4667 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4668 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
4669 | .name = "Master Playback Switch", | ||
4670 | .info = snd_hda_mixer_amp_switch_info, | ||
4671 | .get = snd_hda_mixer_amp_switch_get, | ||
4672 | .put = ad1884a_mobile_master_sw_put, | ||
4673 | .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), | ||
4674 | }, | ||
4675 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), | ||
4676 | HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), | ||
4677 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
4678 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
4679 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT), | ||
4680 | HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x17, 0x0, HDA_INPUT), | ||
4681 | { } /* end */ | ||
4682 | }; | ||
4683 | |||
4684 | /* switch to external mic if plugged */ | ||
4685 | static void ad1984a_touchsmart_automic(struct hda_codec *codec) | ||
4686 | { | ||
4687 | if (snd_hda_jack_detect(codec, 0x1c)) | ||
4688 | snd_hda_codec_write(codec, 0x0c, 0, | ||
4689 | AC_VERB_SET_CONNECT_SEL, 0x4); | ||
4690 | else | ||
4691 | snd_hda_codec_write(codec, 0x0c, 0, | ||
4692 | AC_VERB_SET_CONNECT_SEL, 0x5); | ||
4693 | } | ||
4694 | |||
4695 | |||
4696 | /* unsolicited event for HP jack sensing */ | ||
4697 | static void ad1984a_touchsmart_unsol_event(struct hda_codec *codec, | ||
4698 | unsigned int res) | ||
4699 | { | ||
4700 | switch (res >> 26) { | ||
4701 | case AD1884A_HP_EVENT: | ||
4702 | ad1884a_hp_automute(codec); | ||
4703 | break; | ||
4704 | case AD1884A_MIC_EVENT: | ||
4705 | ad1984a_touchsmart_automic(codec); | ||
4706 | break; | ||
4707 | } | ||
4708 | } | ||
4709 | |||
4710 | /* initialize jack-sensing, too */ | ||
4711 | static int ad1984a_touchsmart_init(struct hda_codec *codec) | ||
4712 | { | ||
4713 | ad198x_init(codec); | ||
4714 | ad1884a_hp_automute(codec); | ||
4715 | ad1984a_touchsmart_automic(codec); | ||
4716 | return 0; | ||
4717 | } | ||
4718 | |||
4719 | |||
4720 | /* | ||
4721 | */ | ||
4722 | |||
4723 | enum { | ||
4724 | AD1884A_AUTO, | ||
4725 | AD1884A_DESKTOP, | ||
4726 | AD1884A_LAPTOP, | ||
4727 | AD1884A_MOBILE, | ||
4728 | AD1884A_THINKPAD, | ||
4729 | AD1984A_TOUCHSMART, | ||
4730 | AD1984A_PRECISION, | ||
4731 | AD1884A_MODELS | ||
4732 | }; | ||
4733 | |||
4734 | static const char * const ad1884a_models[AD1884A_MODELS] = { | ||
4735 | [AD1884A_AUTO] = "auto", | ||
4736 | [AD1884A_DESKTOP] = "desktop", | ||
4737 | [AD1884A_LAPTOP] = "laptop", | ||
4738 | [AD1884A_MOBILE] = "mobile", | ||
4739 | [AD1884A_THINKPAD] = "thinkpad", | ||
4740 | [AD1984A_TOUCHSMART] = "touchsmart", | ||
4741 | [AD1984A_PRECISION] = "precision", | ||
4742 | }; | ||
4743 | |||
4744 | static const struct snd_pci_quirk ad1884a_cfg_tbl[] = { | ||
4745 | SND_PCI_QUIRK(0x1028, 0x04ac, "Precision R5500", AD1984A_PRECISION), | ||
4746 | SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE), | ||
4747 | SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP), | ||
4748 | SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE), | ||
4749 | SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x3070, "HP", AD1884A_MOBILE), | ||
4750 | SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30d0, "HP laptop", AD1884A_LAPTOP), | ||
4751 | SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30e0, "HP laptop", AD1884A_LAPTOP), | ||
4752 | SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3600, "HP laptop", AD1884A_LAPTOP), | ||
4753 | SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x7010, "HP laptop", AD1884A_MOBILE), | ||
4754 | SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD), | ||
4755 | SND_PCI_QUIRK(0x103c, 0x2a82, "Touchsmart", AD1984A_TOUCHSMART), | ||
4756 | {} | ||
4757 | }; | ||
4758 | |||
4759 | static int patch_ad1884a(struct hda_codec *codec) | ||
4760 | { | ||
4761 | struct ad198x_spec *spec; | ||
4762 | int err, board_config; | ||
4763 | |||
4764 | board_config = snd_hda_check_board_config(codec, AD1884A_MODELS, | ||
4765 | ad1884a_models, | ||
4766 | ad1884a_cfg_tbl); | ||
4767 | if (board_config < 0) { | ||
4768 | printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", | ||
4769 | codec->chip_name); | ||
4770 | board_config = AD1884A_AUTO; | ||
4771 | } | ||
4772 | |||
4773 | if (board_config == AD1884A_AUTO) | ||
4774 | return ad1884_parse_auto_config(codec); | ||
4775 | |||
4776 | err = alloc_ad_spec(codec); | ||
4777 | if (err < 0) | ||
4778 | return err; | ||
4779 | spec = codec->spec; | ||
4780 | |||
4781 | err = snd_hda_attach_beep_device(codec, 0x10); | ||
4782 | if (err < 0) { | ||
4783 | ad198x_free(codec); | ||
4784 | return err; | ||
4785 | } | ||
4786 | set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); | ||
4787 | |||
4788 | spec->multiout.max_channels = 2; | ||
4789 | spec->multiout.num_dacs = ARRAY_SIZE(ad1884a_dac_nids); | ||
4790 | spec->multiout.dac_nids = ad1884a_dac_nids; | ||
4791 | spec->multiout.dig_out_nid = AD1884A_SPDIF_OUT; | ||
4792 | spec->num_adc_nids = ARRAY_SIZE(ad1884a_adc_nids); | ||
4793 | spec->adc_nids = ad1884a_adc_nids; | ||
4794 | spec->capsrc_nids = ad1884a_capsrc_nids; | ||
4795 | spec->input_mux = &ad1884a_capture_source; | ||
4796 | spec->num_mixers = 1; | ||
4797 | spec->mixers[0] = ad1884a_base_mixers; | ||
4798 | spec->num_init_verbs = 1; | ||
4799 | spec->init_verbs[0] = ad1884a_init_verbs; | ||
4800 | spec->spdif_route = 0; | ||
4801 | #ifdef CONFIG_PM | ||
4802 | spec->loopback.amplist = ad1884a_loopbacks; | ||
4803 | #endif | ||
4804 | codec->patch_ops = ad198x_patch_ops; | ||
4805 | |||
4806 | /* override some parameters */ | ||
4807 | switch (board_config) { | ||
4808 | case AD1884A_LAPTOP: | ||
4809 | spec->mixers[0] = ad1884a_laptop_mixers; | ||
4810 | spec->init_verbs[spec->num_init_verbs++] = ad1884a_laptop_verbs; | ||
4811 | spec->multiout.dig_out_nid = 0; | ||
4812 | codec->patch_ops.unsol_event = ad1884a_laptop_unsol_event; | ||
4813 | codec->patch_ops.init = ad1884a_laptop_init; | ||
4814 | /* set the upper-limit for mixer amp to 0dB for avoiding the | ||
4815 | * possible damage by overloading | ||
4816 | */ | ||
4817 | snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT, | ||
4818 | (0x17 << AC_AMPCAP_OFFSET_SHIFT) | | ||
4819 | (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | | ||
4820 | (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | | ||
4821 | (1 << AC_AMPCAP_MUTE_SHIFT)); | ||
4822 | break; | ||
4823 | case AD1884A_MOBILE: | ||
4824 | spec->mixers[0] = ad1884a_mobile_mixers; | ||
4825 | spec->init_verbs[0] = ad1884a_mobile_verbs; | ||
4826 | spec->multiout.dig_out_nid = 0; | ||
4827 | codec->patch_ops.unsol_event = ad1884a_hp_unsol_event; | ||
4828 | codec->patch_ops.init = ad1884a_hp_init; | ||
4829 | /* set the upper-limit for mixer amp to 0dB for avoiding the | ||
4830 | * possible damage by overloading | ||
4831 | */ | ||
4832 | snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT, | ||
4833 | (0x17 << AC_AMPCAP_OFFSET_SHIFT) | | ||
4834 | (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | | ||
4835 | (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | | ||
4836 | (1 << AC_AMPCAP_MUTE_SHIFT)); | ||
4837 | break; | ||
4838 | case AD1884A_THINKPAD: | ||
4839 | spec->mixers[0] = ad1984a_thinkpad_mixers; | ||
4840 | spec->init_verbs[spec->num_init_verbs++] = | ||
4841 | ad1984a_thinkpad_verbs; | ||
4842 | spec->multiout.dig_out_nid = 0; | ||
4843 | spec->input_mux = &ad1984a_thinkpad_capture_source; | ||
4844 | codec->patch_ops.unsol_event = ad1984a_thinkpad_unsol_event; | ||
4845 | codec->patch_ops.init = ad1984a_thinkpad_init; | ||
4846 | break; | ||
4847 | case AD1984A_PRECISION: | ||
4848 | spec->mixers[0] = ad1984a_precision_mixers; | ||
4849 | spec->init_verbs[spec->num_init_verbs++] = | ||
4850 | ad1984a_precision_verbs; | ||
4851 | spec->multiout.dig_out_nid = 0; | ||
4852 | codec->patch_ops.unsol_event = ad1984a_precision_unsol_event; | ||
4853 | codec->patch_ops.init = ad1984a_precision_init; | ||
4854 | break; | ||
4855 | case AD1984A_TOUCHSMART: | ||
4856 | spec->mixers[0] = ad1984a_touchsmart_mixers; | ||
4857 | spec->init_verbs[0] = ad1984a_touchsmart_verbs; | ||
4858 | spec->multiout.dig_out_nid = 0; | ||
4859 | codec->patch_ops.unsol_event = ad1984a_touchsmart_unsol_event; | ||
4860 | codec->patch_ops.init = ad1984a_touchsmart_init; | ||
4861 | /* set the upper-limit for mixer amp to 0dB for avoiding the | ||
4862 | * possible damage by overloading | ||
4863 | */ | ||
4864 | snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT, | ||
4865 | (0x17 << AC_AMPCAP_OFFSET_SHIFT) | | ||
4866 | (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | | ||
4867 | (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | | ||
4868 | (1 << AC_AMPCAP_MUTE_SHIFT)); | ||
4869 | break; | ||
4870 | } | ||
4871 | |||
4872 | codec->no_trigger_sense = 1; | ||
4873 | codec->no_sticky_stream = 1; | ||
4874 | |||
4875 | return 0; | ||
4876 | } | ||
4877 | #else /* ENABLE_AD_STATIC_QUIRKS */ | ||
4878 | #define patch_ad1884a ad1884_parse_auto_config | ||
4879 | #endif /* ENABLE_AD_STATIC_QUIRKS */ | ||
4880 | |||
4881 | |||
4882 | /* | 3570 | /* |
4883 | * AD1882 / AD1882A | 3571 | * AD1882 / AD1882A |
4884 | * | 3572 | * |
@@ -4923,15 +3611,15 @@ static int patch_ad1882(struct hda_codec *codec) | |||
4923 | * patch entries | 3611 | * patch entries |
4924 | */ | 3612 | */ |
4925 | static const struct hda_codec_preset snd_hda_preset_analog[] = { | 3613 | static const struct hda_codec_preset snd_hda_preset_analog[] = { |
4926 | { .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884a }, | 3614 | { .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884 }, |
4927 | { .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 }, | 3615 | { .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 }, |
4928 | { .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884a }, | 3616 | { .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884 }, |
4929 | { .id = 0x11d41884, .name = "AD1884", .patch = patch_ad1884 }, | 3617 | { .id = 0x11d41884, .name = "AD1884", .patch = patch_ad1884 }, |
4930 | { .id = 0x11d4194a, .name = "AD1984A", .patch = patch_ad1884a }, | 3618 | { .id = 0x11d4194a, .name = "AD1984A", .patch = patch_ad1884 }, |
4931 | { .id = 0x11d4194b, .name = "AD1984B", .patch = patch_ad1884a }, | 3619 | { .id = 0x11d4194b, .name = "AD1984B", .patch = patch_ad1884 }, |
4932 | { .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 }, | 3620 | { .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 }, |
4933 | { .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 }, | 3621 | { .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 }, |
4934 | { .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1984 }, | 3622 | { .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1884 }, |
4935 | { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a }, | 3623 | { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a }, |
4936 | { .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 }, | 3624 | { .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 }, |
4937 | { .id = 0x11d4198b, .name = "AD1988B", .patch = patch_ad1988 }, | 3625 | { .id = 0x11d4198b, .name = "AD1988B", .patch = patch_ad1988 }, |