Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[ALSA] hda-codec - Add ALC861VD Lenovo support

- Added ALC861VD Lenovo support (17aa:3802, 17aa:2066)
- Modify alc_subsystem_id

Signed-off-by: Kailang Yang <kailang@realtek.com.tw>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>

authored by

Kailang Yang and committed by
Jaroslav Kysela
bdd148a3 0bbed758

+161 -5
+2
Documentation/sound/alsa/ALSA-Configuration.txt
··· 821 821 6stack-dig 6-jack digital with SPDIF I/O 822 822 arima Arima W820Di1 823 823 macpro MacPro support 824 + w2jc ASUS W2JC 824 825 auto auto-config reading BIOS (default) 825 826 826 827 ALC883/888 ··· 853 852 3stack-dig 3-jack with SPDIF OUT 854 853 6stack-dig 6-jack with SPDIF OUT 855 854 3stack-660 3-jack (for ALC660VD) 855 + lenovo Lenovo 3000 C200 856 856 auto auto-config reading BIOS (default) 857 857 858 858 CMI9880
+159 -5
sound/pci/hda/patch_realtek.c
··· 117 117 ALC861VD_3ST, 118 118 ALC861VD_3ST_DIG, 119 119 ALC861VD_6ST_DIG, 120 + ALC861VD_LENOVO, 120 121 ALC861VD_AUTO, 121 122 ALC861VD_MODEL_LAST, 122 123 }; ··· 138 137 ALC882_3ST_DIG, 139 138 ALC882_6ST_DIG, 140 139 ALC882_ARIMA, 140 + ALC882_W2JC, 141 141 ALC882_AUTO, 142 142 ALC885_MACPRO, 143 143 ALC882_MODEL_LAST, ··· 637 635 { } 638 636 }; 639 637 638 + static struct hda_verb alc_gpio3_init_verbs[] = { 639 + {0x01, AC_VERB_SET_GPIO_MASK, 0x03}, 640 + {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03}, 641 + {0x01, AC_VERB_SET_GPIO_DATA, 0x03}, 642 + { } 643 + }; 644 + 640 645 /* 32-bit subsystem ID for BIOS loading in HD Audio codec. 641 646 * 31 ~ 16 : Manufacture ID 642 647 * 15 ~ 8 : SKU ID ··· 669 660 case 3: 670 661 snd_hda_sequence_write(codec, alc_gpio2_init_verbs); 671 662 break; 663 + case 7: 664 + snd_hda_sequence_write(codec, alc_gpio3_init_verbs); 665 + break; 672 666 case 5: 667 + switch (codec->vendor_id) { 668 + case 0x10ec0862: 669 + case 0x10ec0660: 670 + case 0x10ec0662: 671 + case 0x10ec0267: 672 + case 0x10ec0268: 673 + snd_hda_codec_write(codec, 0x14, 0, 674 + AC_VERB_SET_EAPD_BTLENABLE, 2); 675 + snd_hda_codec_write(codec, 0x15, 0, 676 + AC_VERB_SET_EAPD_BTLENABLE, 2); 677 + return; 678 + } 673 679 case 6: 674 680 if (ass & 4) { /* bit 2 : 0 = Desktop, 1 = Laptop */ 675 681 hda_nid_t port = 0; ··· 4809 4785 { } /* end */ 4810 4786 }; 4811 4787 4788 + static struct snd_kcontrol_new alc882_w2jc_mixer[] = { 4789 + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), 4790 + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), 4791 + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), 4792 + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), 4793 + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), 4794 + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), 4795 + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), 4796 + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), 4797 + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), 4798 + HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), 4799 + HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), 4800 + { } /* end */ 4801 + }; 4802 + 4812 4803 static struct snd_kcontrol_new alc882_chmode_mixer[] = { 4813 4804 { 4814 4805 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ··· 5143 5104 [ALC882_3ST_DIG] = "3stack-dig", 5144 5105 [ALC882_6ST_DIG] = "6stack-dig", 5145 5106 [ALC882_ARIMA] = "arima", 5107 + [ALC882_W2JC] = "w2jc", 5146 5108 [ALC885_MACPRO] = "macpro", 5147 5109 [ALC882_AUTO] = "auto", 5148 5110 }; ··· 5154 5114 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG), 5155 5115 SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), 5156 5116 SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG), 5117 + SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC), 5157 5118 {} 5158 5119 }; 5159 5120 ··· 5190 5149 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes), 5191 5150 .channel_mode = alc882_sixstack_modes, 5192 5151 .input_mux = &alc882_capture_source, 5152 + }, 5153 + [ALC882_W2JC] = { 5154 + .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer }, 5155 + .init_verbs = { alc882_init_verbs, alc882_eapd_verbs, 5156 + alc880_gpio1_init_verbs }, 5157 + .num_dacs = ARRAY_SIZE(alc882_dac_nids), 5158 + .dac_nids = alc882_dac_nids, 5159 + .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), 5160 + .channel_mode = alc880_threestack_modes, 5161 + .need_dac_fix = 1, 5162 + .input_mux = &alc882_capture_source, 5163 + .dig_out_nid = ALC882_DIGOUT_NID, 5193 5164 }, 5194 5165 [ALC885_MACPRO] = { 5195 5166 .mixers = { alc882_macpro_mixer }, ··· 8761 8708 { } /* end */ 8762 8709 }; 8763 8710 8711 + static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = { 8712 + HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), 8713 + /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/ 8714 + HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), 8715 + 8716 + HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), 8717 + 8718 + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), 8719 + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), 8720 + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), 8721 + 8722 + HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), 8723 + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), 8724 + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), 8725 + 8726 + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), 8727 + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), 8728 + 8729 + { } /* end */ 8730 + }; 8731 + 8764 8732 /* 8765 8733 * generic initialization of ADC, input mixers and output mixers 8766 8734 */ ··· 8803 8729 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, 8804 8730 8805 8731 /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */ 8732 + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 8733 + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 8734 + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, 8806 8735 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, 8807 - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)}, 8808 - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(6)}, 8809 - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(8)}, 8810 8736 8811 8737 /* 8812 8738 * Set up output mixers (0x02 - 0x05) ··· 8907 8833 { } 8908 8834 }; 8909 8835 8836 + static struct hda_verb alc861vd_eapd_verbs[] = { 8837 + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, 8838 + { } 8839 + }; 8840 + 8841 + static struct hda_verb alc861vd_lenovo_unsol_verbs[] = { 8842 + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 8843 + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 8844 + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, 8845 + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, 8846 + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, 8847 + {} 8848 + }; 8849 + 8850 + /* toggle speaker-output according to the hp-jack state */ 8851 + static void alc861vd_lenovo_hp_automute(struct hda_codec *codec) 8852 + { 8853 + unsigned int present; 8854 + unsigned char bits; 8855 + 8856 + present = snd_hda_codec_read(codec, 0x1b, 0, 8857 + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; 8858 + bits = present ? 0x80 : 0; 8859 + snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, 8860 + 0x80, bits); 8861 + snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, 8862 + 0x80, bits); 8863 + } 8864 + 8865 + static void alc861vd_lenovo_mic_automute(struct hda_codec *codec) 8866 + { 8867 + unsigned int present; 8868 + unsigned char bits; 8869 + 8870 + present = snd_hda_codec_read(codec, 0x18, 0, 8871 + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; 8872 + bits = present ? 0x80 : 0; 8873 + snd_hda_codec_amp_update(codec, 0x0b, 0, HDA_INPUT, 1, 8874 + 0x80, bits); 8875 + snd_hda_codec_amp_update(codec, 0x0b, 1, HDA_INPUT, 1, 8876 + 0x80, bits); 8877 + } 8878 + 8879 + static void alc861vd_lenovo_automute(struct hda_codec *codec) 8880 + { 8881 + alc861vd_lenovo_hp_automute(codec); 8882 + alc861vd_lenovo_mic_automute(codec); 8883 + } 8884 + 8885 + static void alc861vd_lenovo_unsol_event(struct hda_codec *codec, 8886 + unsigned int res) 8887 + { 8888 + switch (res >> 26) { 8889 + case ALC880_HP_EVENT: 8890 + alc861vd_lenovo_hp_automute(codec); 8891 + break; 8892 + case ALC880_MIC_EVENT: 8893 + alc861vd_lenovo_mic_automute(codec); 8894 + break; 8895 + } 8896 + } 8897 + 8910 8898 /* pcm configuration: identiacal with ALC880 */ 8911 8899 #define alc861vd_pcm_analog_playback alc880_pcm_analog_playback 8912 8900 #define alc861vd_pcm_analog_capture alc880_pcm_analog_capture ··· 8983 8847 [ALC861VD_3ST] = "3stack", 8984 8848 [ALC861VD_3ST_DIG] = "3stack-digout", 8985 8849 [ALC861VD_6ST_DIG] = "6stack-digout", 8850 + [ALC861VD_LENOVO] = "lenovo", 8986 8851 [ALC861VD_AUTO] = "auto", 8987 8852 }; 8988 8853 ··· 8993 8856 SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST), 8994 8857 SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST), 8995 8858 8996 - SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_3ST), 8859 + SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO), 8860 + SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO), 8997 8861 {} 8998 8862 }; 8999 8863 ··· 9042 8904 .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes), 9043 8905 .channel_mode = alc861vd_6stack_modes, 9044 8906 .input_mux = &alc861vd_capture_source, 8907 + }, 8908 + [ALC861VD_LENOVO] = { 8909 + .mixers = { alc861vd_lenovo_mixer }, 8910 + .init_verbs = { alc861vd_volume_init_verbs, 8911 + alc861vd_3stack_init_verbs, 8912 + alc861vd_eapd_verbs, 8913 + alc861vd_lenovo_unsol_verbs }, 8914 + .num_dacs = ARRAY_SIZE(alc660vd_dac_nids), 8915 + .dac_nids = alc660vd_dac_nids, 8916 + .num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids), 8917 + .adc_nids = alc861vd_adc_nids, 8918 + .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), 8919 + .channel_mode = alc861vd_3stack_2ch_modes, 8920 + .input_mux = &alc861vd_capture_source, 8921 + .unsol_event = alc861vd_lenovo_unsol_event, 8922 + .init_hook = alc861vd_lenovo_automute, 9045 8923 }, 9046 8924 }; 9047 8925 ··· 9182 9028 return err; 9183 9029 sprintf(name, "%s Playback Switch", chname[i]); 9184 9030 err = add_control(spec, ALC_CTL_BIND_MUTE, name, 9185 - HDA_COMPOSE_AMP_VAL(nid_v, 3, 2, 9031 + HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, 9186 9032 HDA_INPUT)); 9187 9033 if (err < 0) 9188 9034 return err;