aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda
diff options
context:
space:
mode:
authorKailang Yang <kailang@realtek.com.tw>2007-04-12 07:06:07 -0400
committerJaroslav Kysela <perex@suse.cz>2007-05-11 10:55:58 -0400
commitbc9f98a9815c452a74e5eb9cbd2ed61b337fdcd2 (patch)
treedd8e465a66fa8082ff50fa04eedadc7d95a36512 /sound/pci/hda
parent7d4b4380d37025f0b13ae951e0cb2ff7184dc5bb (diff)
[ALSA] hda-codec - Add ALC662 support
- Add ALC662 support - Fixed no sound for [0x1631, 0xc017, 'PB V7900', ALC260_WILL] - Fixed no sound for [0x161f, 0x2057, 'Replacer 672V', ALC260_REPLACER_672V] - Add SKU ID for auto mode 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>
Diffstat (limited to 'sound/pci/hda')
-rw-r--r--sound/pci/hda/patch_realtek.c1162
1 files changed, 1139 insertions, 23 deletions
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index d3f7a3dab1c4..5d7f61982001 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -74,6 +74,8 @@ enum {
74 ALC260_HP_3013, 74 ALC260_HP_3013,
75 ALC260_FUJITSU_S702X, 75 ALC260_FUJITSU_S702X,
76 ALC260_ACER, 76 ALC260_ACER,
77 ALC260_WILL,
78 ALC260_REPLACER_672V,
77#ifdef CONFIG_SND_DEBUG 79#ifdef CONFIG_SND_DEBUG
78 ALC260_TEST, 80 ALC260_TEST,
79#endif 81#endif
@@ -119,6 +121,17 @@ enum {
119 ALC861VD_MODEL_LAST, 121 ALC861VD_MODEL_LAST,
120}; 122};
121 123
124/* ALC662 models */
125enum {
126 ALC662_3ST_2ch_DIG,
127 ALC662_3ST_6ch_DIG,
128 ALC662_3ST_6ch,
129 ALC662_5ST_DIG,
130 ALC662_LENOVO_101E,
131 ALC662_AUTO,
132 ALC662_MODEL_LAST,
133};
134
122/* ALC882 models */ 135/* ALC882 models */
123enum { 136enum {
124 ALC882_3ST_DIG, 137 ALC882_3ST_DIG,
@@ -141,6 +154,7 @@ enum {
141 ALC883_ACER, 154 ALC883_ACER,
142 ALC883_MEDION, 155 ALC883_MEDION,
143 ALC883_LAPTOP_EAPD, 156 ALC883_LAPTOP_EAPD,
157 ALC883_LENOVO_101E_2ch,
144 ALC883_AUTO, 158 ALC883_AUTO,
145 ALC883_MODEL_LAST, 159 ALC883_MODEL_LAST,
146}; 160};
@@ -604,6 +618,68 @@ static void setup_preset(struct alc_spec *spec,
604 spec->init_hook = preset->init_hook; 618 spec->init_hook = preset->init_hook;
605} 619}
606 620
621/* Enable GPIO mask and set output */
622static struct hda_verb alc_gpio1_init_verbs[] = {
623 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
624 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
625 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
626 { }
627};
628
629static struct hda_verb alc_gpio2_init_verbs[] = {
630 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
631 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
632 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
633 { }
634};
635
636/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
637 * 31 ~ 16 : Manufacture ID
638 * 15 ~ 8 : SKU ID
639 * 7 ~ 0 : Assembly ID
640 * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
641 */
642static void alc_subsystem_id(struct hda_codec *codec,
643 unsigned int porta, unsigned int porte,
644 unsigned int portd)
645{
646 unsigned int ass, tmp;
647
648 ass = codec->subsystem_id;
649 if (!(ass & 1))
650 return;
651
652 /* Override */
653 tmp = (ass & 0x38) >> 3; /* external Amp control */
654 switch (tmp) {
655 case 1:
656 snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
657 break;
658 case 3:
659 snd_hda_sequence_write(codec, alc_gpio2_init_verbs);
660 break;
661 case 5:
662 case 6:
663 if (ass & 4) { /* bit 2 : 0 = Desktop, 1 = Laptop */
664 hda_nid_t port = 0;
665 tmp = (ass & 0x1800) >> 11;
666 switch (tmp) {
667 case 0: port = porta; break;
668 case 1: port = porte; break;
669 case 2: port = portd; break;
670 }
671 if (port)
672 snd_hda_codec_write(codec, port, 0,
673 AC_VERB_SET_EAPD_BTLENABLE,
674 2);
675 }
676 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
677 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF,
678 (tmp == 5 ? 0x3040 : 0x3050));
679 break;
680 }
681}
682
607/* 683/*
608 * ALC880 3-stack model 684 * ALC880 3-stack model
609 * 685 *
@@ -1547,22 +1623,8 @@ static struct hda_verb alc880_pin_asus_init_verbs[] = {
1547}; 1623};
1548 1624
1549/* Enable GPIO mask and set output */ 1625/* Enable GPIO mask and set output */
1550static struct hda_verb alc880_gpio1_init_verbs[] = { 1626#define alc880_gpio1_init_verbs alc_gpio1_init_verbs
1551 {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, 1627#define alc880_gpio2_init_verbs alc_gpio2_init_verbs
1552 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
1553 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
1554
1555 { }
1556};
1557
1558/* Enable GPIO mask and set output */
1559static struct hda_verb alc880_gpio2_init_verbs[] = {
1560 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
1561 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
1562 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
1563
1564 { }
1565};
1566 1628
1567/* Clevo m520g init */ 1629/* Clevo m520g init */
1568static struct hda_verb alc880_pin_clevo_init_verbs[] = { 1630static struct hda_verb alc880_pin_clevo_init_verbs[] = {
@@ -2980,7 +3042,8 @@ static void alc880_auto_init_multi_out(struct hda_codec *codec)
2980{ 3042{
2981 struct alc_spec *spec = codec->spec; 3043 struct alc_spec *spec = codec->spec;
2982 int i; 3044 int i;
2983 3045
3046 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
2984 for (i = 0; i < spec->autocfg.line_outs; i++) { 3047 for (i = 0; i < spec->autocfg.line_outs; i++) {
2985 hda_nid_t nid = spec->autocfg.line_out_pins[i]; 3048 hda_nid_t nid = spec->autocfg.line_out_pins[i];
2986 alc880_auto_set_output_and_unmute(codec, nid, PIN_OUT, i); 3049 alc880_auto_set_output_and_unmute(codec, nid, PIN_OUT, i);
@@ -3361,6 +3424,42 @@ static struct snd_kcontrol_new alc260_acer_mixer[] = {
3361 { } /* end */ 3424 { } /* end */
3362}; 3425};
3363 3426
3427/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
3428 * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17.
3429 */
3430static struct snd_kcontrol_new alc260_will_mixer[] = {
3431 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
3432 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
3433 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
3434 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
3435 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
3436 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
3437 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
3438 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
3439 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
3440 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
3441 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
3442 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
3443 { } /* end */
3444};
3445
3446/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
3447 * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
3448 */
3449static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
3450 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
3451 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
3452 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
3453 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
3454 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
3455 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
3456 HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
3457 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
3458 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
3459 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
3460 { } /* end */
3461};
3462
3364/* capture mixer elements */ 3463/* capture mixer elements */
3365static struct snd_kcontrol_new alc260_capture_mixer[] = { 3464static struct snd_kcontrol_new alc260_capture_mixer[] = {
3366 HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT), 3465 HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT),
@@ -3731,6 +3830,55 @@ static struct hda_verb alc260_acer_init_verbs[] = {
3731 { } 3830 { }
3732}; 3831};
3733 3832
3833static struct hda_verb alc260_will_verbs[] = {
3834 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3835 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
3836 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
3837 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
3838 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
3839 {0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
3840 {}
3841};
3842
3843static struct hda_verb alc260_replacer_672v_verbs[] = {
3844 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
3845 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
3846 {0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
3847
3848 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
3849 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
3850 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
3851
3852 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3853 {}
3854};
3855
3856/* toggle speaker-output according to the hp-jack state */
3857static void alc260_replacer_672v_automute(struct hda_codec *codec)
3858{
3859 unsigned int present;
3860
3861 /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
3862 present = snd_hda_codec_read(codec, 0x0f, 0,
3863 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
3864 if (present) {
3865 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 1);
3866 snd_hda_codec_write(codec, 0x0f, 0,
3867 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
3868 } else {
3869 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
3870 snd_hda_codec_write(codec, 0x0f, 0,
3871 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
3872 }
3873}
3874
3875static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
3876 unsigned int res)
3877{
3878 if ((res >> 26) == ALC880_HP_EVENT)
3879 alc260_replacer_672v_automute(codec);
3880}
3881
3734/* Test configuration for debugging, modelled after the ALC880 test 3882/* Test configuration for debugging, modelled after the ALC880 test
3735 * configuration. 3883 * configuration.
3736 */ 3884 */
@@ -4053,6 +4201,7 @@ static void alc260_auto_init_multi_out(struct hda_codec *codec)
4053 struct alc_spec *spec = codec->spec; 4201 struct alc_spec *spec = codec->spec;
4054 hda_nid_t nid; 4202 hda_nid_t nid;
4055 4203
4204 alc_subsystem_id(codec, 0x10, 0x15, 0x0f);
4056 nid = spec->autocfg.line_out_pins[0]; 4205 nid = spec->autocfg.line_out_pins[0];
4057 if (nid) 4206 if (nid)
4058 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0); 4207 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
@@ -4189,6 +4338,8 @@ static const char *alc260_models[ALC260_MODEL_LAST] = {
4189 [ALC260_HP_3013] = "hp-3013", 4338 [ALC260_HP_3013] = "hp-3013",
4190 [ALC260_FUJITSU_S702X] = "fujitsu", 4339 [ALC260_FUJITSU_S702X] = "fujitsu",
4191 [ALC260_ACER] = "acer", 4340 [ALC260_ACER] = "acer",
4341 [ALC260_WILL] = "will",
4342 [ALC260_REPLACER_672V] = "replacer",
4192#ifdef CONFIG_SND_DEBUG 4343#ifdef CONFIG_SND_DEBUG
4193 [ALC260_TEST] = "test", 4344 [ALC260_TEST] = "test",
4194#endif 4345#endif
@@ -4212,6 +4363,8 @@ static struct snd_pci_quirk alc260_cfg_tbl[] = {
4212 SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC), 4363 SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
4213 SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X), 4364 SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
4214 SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC), 4365 SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
4366 SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
4367 SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
4215 {} 4368 {}
4216}; 4369};
4217 4370
@@ -4282,6 +4435,34 @@ static struct alc_config_preset alc260_presets[] = {
4282 .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources), 4435 .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
4283 .input_mux = alc260_acer_capture_sources, 4436 .input_mux = alc260_acer_capture_sources,
4284 }, 4437 },
4438 [ALC260_WILL] = {
4439 .mixers = { alc260_will_mixer,
4440 alc260_capture_mixer },
4441 .init_verbs = { alc260_init_verbs, alc260_will_verbs },
4442 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
4443 .dac_nids = alc260_dac_nids,
4444 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
4445 .adc_nids = alc260_adc_nids,
4446 .dig_out_nid = ALC260_DIGOUT_NID,
4447 .num_channel_mode = ARRAY_SIZE(alc260_modes),
4448 .channel_mode = alc260_modes,
4449 .input_mux = &alc260_capture_source,
4450 },
4451 [ALC260_REPLACER_672V] = {
4452 .mixers = { alc260_replacer_672v_mixer,
4453 alc260_capture_mixer },
4454 .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
4455 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
4456 .dac_nids = alc260_dac_nids,
4457 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
4458 .adc_nids = alc260_adc_nids,
4459 .dig_out_nid = ALC260_DIGOUT_NID,
4460 .num_channel_mode = ARRAY_SIZE(alc260_modes),
4461 .channel_mode = alc260_modes,
4462 .input_mux = &alc260_capture_source,
4463 .unsol_event = alc260_replacer_672v_unsol_event,
4464 .init_hook = alc260_replacer_672v_automute,
4465 },
4285#ifdef CONFIG_SND_DEBUG 4466#ifdef CONFIG_SND_DEBUG
4286 [ALC260_TEST] = { 4467 [ALC260_TEST] = {
4287 .mixers = { alc260_test_mixer, 4468 .mixers = { alc260_test_mixer,
@@ -4881,6 +5062,7 @@ static void alc882_auto_init_multi_out(struct hda_codec *codec)
4881 struct alc_spec *spec = codec->spec; 5062 struct alc_spec *spec = codec->spec;
4882 int i; 5063 int i;
4883 5064
5065 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
4884 for (i = 0; i <= HDA_SIDE; i++) { 5066 for (i = 0; i <= HDA_SIDE; i++) {
4885 hda_nid_t nid = spec->autocfg.line_out_pins[i]; 5067 hda_nid_t nid = spec->autocfg.line_out_pins[i];
4886 if (nid) 5068 if (nid)
@@ -5057,6 +5239,15 @@ static struct hda_input_mux alc883_capture_source = {
5057 { "CD", 0x4 }, 5239 { "CD", 0x4 },
5058 }, 5240 },
5059}; 5241};
5242
5243static struct hda_input_mux alc883_lenovo_101e_capture_source = {
5244 .num_items = 2,
5245 .items = {
5246 { "Mic", 0x1 },
5247 { "Line", 0x2 },
5248 },
5249};
5250
5060#define alc883_mux_enum_info alc_mux_enum_info 5251#define alc883_mux_enum_info alc_mux_enum_info
5061#define alc883_mux_enum_get alc_mux_enum_get 5252#define alc883_mux_enum_get alc_mux_enum_get
5062 5253
@@ -5364,6 +5555,29 @@ static struct snd_kcontrol_new alc883_tagra_2ch_mixer[] = {
5364 { } /* end */ 5555 { } /* end */
5365}; 5556};
5366 5557
5558static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
5559 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5560 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5561 HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
5562 HDA_BIND_MUTE("iSpeaker Playback Switch", 0x0d, 2, HDA_INPUT),
5563 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
5564 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
5565 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
5566 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
5567 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
5568 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
5569 {
5570 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5571 /* .name = "Capture Source", */
5572 .name = "Input Source",
5573 .count = 1,
5574 .info = alc883_mux_enum_info,
5575 .get = alc883_mux_enum_get,
5576 .put = alc883_mux_enum_put,
5577 },
5578 { } /* end */
5579};
5580
5367static struct snd_kcontrol_new alc883_chmode_mixer[] = { 5581static struct snd_kcontrol_new alc883_chmode_mixer[] = {
5368 { 5582 {
5369 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 5583 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -5471,6 +5685,13 @@ static struct hda_verb alc883_tagra_verbs[] = {
5471 { } /* end */ 5685 { } /* end */
5472}; 5686};
5473 5687
5688static struct hda_verb alc883_lenovo_101e_verbs[] = {
5689 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
5690 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
5691 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
5692 { } /* end */
5693};
5694
5474/* toggle speaker-output according to the hp-jack state */ 5695/* toggle speaker-output according to the hp-jack state */
5475static void alc883_tagra_automute(struct hda_codec *codec) 5696static void alc883_tagra_automute(struct hda_codec *codec)
5476{ 5697{
@@ -5491,6 +5712,45 @@ static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res)
5491 alc883_tagra_automute(codec); 5712 alc883_tagra_automute(codec);
5492} 5713}
5493 5714
5715static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
5716{
5717 unsigned int present;
5718
5719 present = snd_hda_codec_read(codec, 0x14, 0,
5720 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
5721
5722 snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0,
5723 0x80, present ? 0x80 : 0);
5724 snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0,
5725 0x80, present ? 0x80 : 0);
5726}
5727
5728static void alc883_lenovo_101e_all_automute(struct hda_codec *codec)
5729{
5730 unsigned int present;
5731
5732 present = snd_hda_codec_read(codec, 0x1b, 0,
5733 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
5734
5735 snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0,
5736 0x80, present ? 0x80 : 0);
5737 snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0,
5738 0x80, present ? 0x80 : 0);
5739 snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
5740 0x80, present ? 0x80 : 0);
5741 snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
5742 0x80, present ? 0x80 : 0);
5743}
5744
5745static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec,
5746 unsigned int res)
5747{
5748 if ((res >> 26) == ALC880_HP_EVENT)
5749 alc883_lenovo_101e_all_automute(codec);
5750 if ((res >> 26) == ALC880_FRONT_EVENT)
5751 alc883_lenovo_101e_ispeaker_automute(codec);
5752}
5753
5494/* 5754/*
5495 * generic initialization of ADC, input mixers and output mixers 5755 * generic initialization of ADC, input mixers and output mixers
5496 */ 5756 */
@@ -5596,6 +5856,7 @@ static const char *alc883_models[ALC883_MODEL_LAST] = {
5596 [ALC883_ACER] = "acer", 5856 [ALC883_ACER] = "acer",
5597 [ALC883_MEDION] = "medion", 5857 [ALC883_MEDION] = "medion",
5598 [ALC883_LAPTOP_EAPD] = "laptop-eapd", 5858 [ALC883_LAPTOP_EAPD] = "laptop-eapd",
5859 [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
5599 [ALC883_AUTO] = "auto", 5860 [ALC883_AUTO] = "auto",
5600}; 5861};
5601 5862
@@ -5621,6 +5882,7 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
5621 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION), 5882 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
5622 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD), 5883 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
5623 SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch), 5884 SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
5885 SND_PCI_QUIRK(0x17aa, 0x101e, "lenovo 101e", ALC883_LENOVO_101E_2ch),
5624 {} 5886 {}
5625}; 5887};
5626 5888
@@ -5761,6 +6023,19 @@ static struct alc_config_preset alc883_presets[] = {
5761 .channel_mode = alc883_3ST_2ch_modes, 6023 .channel_mode = alc883_3ST_2ch_modes,
5762 .input_mux = &alc883_capture_source, 6024 .input_mux = &alc883_capture_source,
5763 }, 6025 },
6026 [ALC883_LENOVO_101E_2ch] = {
6027 .mixers = { alc883_lenovo_101e_2ch_mixer},
6028 .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
6029 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
6030 .dac_nids = alc883_dac_nids,
6031 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
6032 .adc_nids = alc883_adc_nids,
6033 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
6034 .channel_mode = alc883_3ST_2ch_modes,
6035 .input_mux = &alc883_lenovo_101e_capture_source,
6036 .unsol_event = alc883_lenovo_101e_unsol_event,
6037 .init_hook = alc883_lenovo_101e_all_automute,
6038 },
5764}; 6039};
5765 6040
5766 6041
@@ -5793,6 +6068,7 @@ static void alc883_auto_init_multi_out(struct hda_codec *codec)
5793 struct alc_spec *spec = codec->spec; 6068 struct alc_spec *spec = codec->spec;
5794 int i; 6069 int i;
5795 6070
6071 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
5796 for (i = 0; i <= HDA_SIDE; i++) { 6072 for (i = 0; i <= HDA_SIDE; i++) {
5797 hda_nid_t nid = spec->autocfg.line_out_pins[i]; 6073 hda_nid_t nid = spec->autocfg.line_out_pins[i];
5798 if (nid) 6074 if (nid)
@@ -5845,8 +6121,8 @@ static int alc883_parse_auto_config(struct hda_codec *codec)
5845 else if (err > 0) 6121 else if (err > 0)
5846 /* hack - override the init verbs */ 6122 /* hack - override the init verbs */
5847 spec->init_verbs[0] = alc883_auto_init_verbs; 6123 spec->init_verbs[0] = alc883_auto_init_verbs;
5848 spec->mixers[spec->num_mixers] = alc883_capture_mixer; 6124 spec->mixers[spec->num_mixers] = alc883_capture_mixer;
5849 spec->num_mixers++; 6125 spec->num_mixers++;
5850 return err; 6126 return err;
5851} 6127}
5852 6128
@@ -7533,9 +7809,6 @@ static void alc861_toshiba_automute(struct hda_codec *codec)
7533static void alc861_toshiba_unsol_event(struct hda_codec *codec, 7809static void alc861_toshiba_unsol_event(struct hda_codec *codec,
7534 unsigned int res) 7810 unsigned int res)
7535{ 7811{
7536 /* Looks like the unsol event is incompatible with the standard
7537 * definition. 6bit tag is placed at 26 bit!
7538 */
7539 if ((res >> 26) == ALC880_HP_EVENT) 7812 if ((res >> 26) == ALC880_HP_EVENT)
7540 alc861_toshiba_automute(codec); 7813 alc861_toshiba_automute(codec);
7541} 7814}
@@ -7729,6 +8002,7 @@ static void alc861_auto_init_multi_out(struct hda_codec *codec)
7729 struct alc_spec *spec = codec->spec; 8002 struct alc_spec *spec = codec->spec;
7730 int i; 8003 int i;
7731 8004
8005 alc_subsystem_id(codec, 0x0e, 0x0f, 0x0b);
7732 for (i = 0; i < spec->autocfg.line_outs; i++) { 8006 for (i = 0; i < spec->autocfg.line_outs; i++) {
7733 hda_nid_t nid = spec->autocfg.line_out_pins[i]; 8007 hda_nid_t nid = spec->autocfg.line_out_pins[i];
7734 if (nid) 8008 if (nid)
@@ -8423,6 +8697,7 @@ static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
8423 struct alc_spec *spec = codec->spec; 8697 struct alc_spec *spec = codec->spec;
8424 int i; 8698 int i;
8425 8699
8700 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
8426 for (i = 0; i <= HDA_SIDE; i++) { 8701 for (i = 0; i <= HDA_SIDE; i++) {
8427 hda_nid_t nid = spec->autocfg.line_out_pins[i]; 8702 hda_nid_t nid = spec->autocfg.line_out_pins[i];
8428 if (nid) 8703 if (nid)
@@ -8689,16 +8964,857 @@ static int patch_alc861vd(struct hda_codec *codec)
8689} 8964}
8690 8965
8691/* 8966/*
8967 * ALC662 support
8968 *
8969 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
8970 * configuration. Each pin widget can choose any input DACs and a mixer.
8971 * Each ADC is connected from a mixer of all inputs. This makes possible
8972 * 6-channel independent captures.
8973 *
8974 * In addition, an independent DAC for the multi-playback (not used in this
8975 * driver yet).
8976 */
8977#define ALC662_DIGOUT_NID 0x06
8978#define ALC662_DIGIN_NID 0x0a
8979
8980static hda_nid_t alc662_dac_nids[4] = {
8981 /* front, rear, clfe, rear_surr */
8982 0x02, 0x03, 0x04
8983};
8984
8985static hda_nid_t alc662_adc_nids[1] = {
8986 /* ADC1-2 */
8987 0x09,
8988};
8989/* input MUX */
8990/* FIXME: should be a matrix-type input source selection */
8991
8992static struct hda_input_mux alc662_capture_source = {
8993 .num_items = 4,
8994 .items = {
8995 { "Mic", 0x0 },
8996 { "Front Mic", 0x1 },
8997 { "Line", 0x2 },
8998 { "CD", 0x4 },
8999 },
9000};
9001
9002static struct hda_input_mux alc662_lenovo_101e_capture_source = {
9003 .num_items = 2,
9004 .items = {
9005 { "Mic", 0x1 },
9006 { "Line", 0x2 },
9007 },
9008};
9009#define alc662_mux_enum_info alc_mux_enum_info
9010#define alc662_mux_enum_get alc_mux_enum_get
9011
9012static int alc662_mux_enum_put(struct snd_kcontrol *kcontrol,
9013 struct snd_ctl_elem_value *ucontrol)
9014{
9015 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9016 struct alc_spec *spec = codec->spec;
9017 const struct hda_input_mux *imux = spec->input_mux;
9018 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
9019 static hda_nid_t capture_mixers[3] = { 0x24, 0x23, 0x22 };
9020 hda_nid_t nid = capture_mixers[adc_idx];
9021 unsigned int *cur_val = &spec->cur_mux[adc_idx];
9022 unsigned int i, idx;
9023
9024 idx = ucontrol->value.enumerated.item[0];
9025 if (idx >= imux->num_items)
9026 idx = imux->num_items - 1;
9027 if (*cur_val == idx && ! codec->in_resume)
9028 return 0;
9029 for (i = 0; i < imux->num_items; i++) {
9030 unsigned int v = (i == idx) ? 0x7000 : 0x7080;
9031 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
9032 v | (imux->items[i].index << 8));
9033 }
9034 *cur_val = idx;
9035 return 1;
9036}
9037/*
9038 * 2ch mode
9039 */
9040static struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
9041 { 2, NULL }
9042};
9043
9044/*
9045 * 2ch mode
9046 */
9047static struct hda_verb alc662_3ST_ch2_init[] = {
9048 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
9049 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
9050 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
9051 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
9052 { } /* end */
9053};
9054
9055/*
9056 * 6ch mode
9057 */
9058static struct hda_verb alc662_3ST_ch6_init[] = {
9059 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9060 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
9061 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
9062 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9063 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
9064 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
9065 { } /* end */
9066};
9067
9068static struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
9069 { 2, alc662_3ST_ch2_init },
9070 { 6, alc662_3ST_ch6_init },
9071};
9072
9073/*
9074 * 2ch mode
9075 */
9076static struct hda_verb alc662_sixstack_ch6_init[] = {
9077 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
9078 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
9079 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9080 { } /* end */
9081};
9082
9083/*
9084 * 6ch mode
9085 */
9086static struct hda_verb alc662_sixstack_ch8_init[] = {
9087 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9088 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9089 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9090 { } /* end */
9091};
9092
9093static struct hda_channel_mode alc662_5stack_modes[2] = {
9094 { 2, alc662_sixstack_ch6_init },
9095 { 6, alc662_sixstack_ch8_init },
9096};
9097
9098/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
9099 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
9100 */
9101
9102static struct snd_kcontrol_new alc662_base_mixer[] = {
9103 /* output mixer control */
9104 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
9105 HDA_CODEC_MUTE("Front Playback Switch", 0x02, 0x0, HDA_OUTPUT),
9106 HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
9107 HDA_CODEC_MUTE("Surround Playback Switch", 0x03, 0x0, HDA_OUTPUT),
9108 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
9109 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
9110 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT),
9111 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT),
9112 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
9113
9114 /*Input mixer control */
9115 HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
9116 HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
9117 HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
9118 HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
9119 HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
9120 HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
9121 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
9122 HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
9123
9124 /* Capture mixer control */
9125 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
9126 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
9127 {
9128 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9129 .name = "Capture Source",
9130 .count = 1,
9131 .info = alc_mux_enum_info,
9132 .get = alc_mux_enum_get,
9133 .put = alc_mux_enum_put,
9134 },
9135 { } /* end */
9136};
9137
9138static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
9139 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
9140 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
9141 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
9142 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9143 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9144 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9145 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9146 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9147 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9148 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
9149 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
9150 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
9151 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
9152 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
9153 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
9154 {
9155 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9156 /* .name = "Capture Source", */
9157 .name = "Input Source",
9158 .count = 1,
9159 .info = alc662_mux_enum_info,
9160 .get = alc662_mux_enum_get,
9161 .put = alc662_mux_enum_put,
9162 },
9163 { } /* end */
9164};
9165
9166static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
9167 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
9168 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
9169 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
9170 HDA_BIND_MUTE("Surround Playback Switch", 0x03, 2, HDA_INPUT),
9171 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
9172 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
9173 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT),
9174 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT),
9175 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
9176 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9177 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9178 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9179 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9180 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9181 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9182 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
9183 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
9184 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
9185 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
9186 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
9187 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
9188 {
9189 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9190 /* .name = "Capture Source", */
9191 .name = "Input Source",
9192 .count = 1,
9193 .info = alc662_mux_enum_info,
9194 .get = alc662_mux_enum_get,
9195 .put = alc662_mux_enum_put,
9196 },
9197 { } /* end */
9198};
9199
9200static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
9201 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
9202 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
9203 HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
9204 HDA_BIND_MUTE("iSpeaker Playback Switch", 0x03, 2, HDA_INPUT),
9205 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
9206 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9207 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9208 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
9209 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
9210 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
9211 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
9212 {
9213 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9214 /* .name = "Capture Source", */
9215 .name = "Input Source",
9216 .count = 1,
9217 .info = alc662_mux_enum_info,
9218 .get = alc662_mux_enum_get,
9219 .put = alc662_mux_enum_put,
9220 },
9221 { } /* end */
9222};
9223
9224static struct snd_kcontrol_new alc662_chmode_mixer[] = {
9225 {
9226 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9227 .name = "Channel Mode",
9228 .info = alc_ch_mode_info,
9229 .get = alc_ch_mode_get,
9230 .put = alc_ch_mode_put,
9231 },
9232 { } /* end */
9233};
9234
9235static struct hda_verb alc662_init_verbs[] = {
9236 /* ADC: mute amp left and right */
9237 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9238 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
9239 /* Front mixer: unmute input/output amp left and right (volume = 0) */
9240
9241 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9242 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9243 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
9244 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
9245 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
9246
9247 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9248 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9249 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9250 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9251 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9252 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9253
9254 /* Front Pin: output 0 (0x0c) */
9255 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9256 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9257
9258 /* Rear Pin: output 1 (0x0d) */
9259 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9260 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9261
9262 /* CLFE Pin: output 2 (0x0e) */
9263 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9264 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9265
9266 /* Mic (rear) pin: input vref at 80% */
9267 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
9268 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9269 /* Front Mic pin: input vref at 80% */
9270 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
9271 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9272 /* Line In pin: input */
9273 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
9274 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9275 /* Line-2 In: Headphone output (output 0 - 0x0c) */
9276 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9277 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9278 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9279 /* CD pin widget for input */
9280 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
9281
9282 /* FIXME: use matrix-type input source selection */
9283 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
9284 /* Input mixer */
9285 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9286 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9287 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
9288 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
9289 { }
9290};
9291
9292static struct hda_verb alc662_sue_init_verbs[] = {
9293 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
9294 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
9295 {}
9296};
9297
9298/*
9299 * generic initialization of ADC, input mixers and output mixers
9300 */
9301static struct hda_verb alc662_auto_init_verbs[] = {
9302 /*
9303 * Unmute ADC and set the default input to mic-in
9304 */
9305 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
9306 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9307
9308 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
9309 * mixer widget
9310 * Note: PASD motherboards uses the Line In 2 as the input for front
9311 * panel mic (mic 2)
9312 */
9313 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
9314 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9315 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9316 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
9317 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
9318 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
9319
9320 /*
9321 * Set up output mixers (0x0c - 0x0f)
9322 */
9323 /* set vol=0 to output mixers */
9324 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9325 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9326 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9327
9328 /* set up input amps for analog loopback */
9329 /* Amp Indices: DAC = 0, mixer = 1 */
9330 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9331 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9332 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9333 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9334 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9335 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9336
9337
9338 /* FIXME: use matrix-type input source selection */
9339 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
9340 /* Input mixer */
9341 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9342 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9343 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
9344 /*{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},*/
9345 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
9346
9347 { }
9348};
9349
9350/* capture mixer elements */
9351static struct snd_kcontrol_new alc662_capture_mixer[] = {
9352 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
9353 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
9354 {
9355 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9356 /* The multiple "Capture Source" controls confuse alsamixer
9357 * So call somewhat different..
9358 * FIXME: the controls appear in the "playback" view!
9359 */
9360 /* .name = "Capture Source", */
9361 .name = "Input Source",
9362 .count = 1,
9363 .info = alc882_mux_enum_info,
9364 .get = alc882_mux_enum_get,
9365 .put = alc882_mux_enum_put,
9366 },
9367 { } /* end */
9368};
9369
9370static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
9371{
9372 unsigned int present;
9373
9374 present = snd_hda_codec_read(codec, 0x14, 0,
9375 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
9376
9377 snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0,
9378 0x80, present ? 0x80 : 0);
9379 snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0,
9380 0x80, present ? 0x80 : 0);
9381}
9382
9383static void alc662_lenovo_101e_all_automute(struct hda_codec *codec)
9384{
9385 unsigned int present;
9386
9387 present = snd_hda_codec_read(codec, 0x1b, 0,
9388 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
9389
9390 snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0,
9391 0x80, present ? 0x80 : 0);
9392 snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0,
9393 0x80, present ? 0x80 : 0);
9394 snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
9395 0x80, present ? 0x80 : 0);
9396 snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
9397 0x80, present ? 0x80 : 0);
9398}
9399
9400static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec,
9401 unsigned int res)
9402{
9403 if ((res >> 26) == ALC880_HP_EVENT)
9404 alc662_lenovo_101e_all_automute(codec);
9405 if ((res >> 26) == ALC880_FRONT_EVENT)
9406 alc662_lenovo_101e_ispeaker_automute(codec);
9407}
9408
9409
9410/* pcm configuration: identiacal with ALC880 */
9411#define alc662_pcm_analog_playback alc880_pcm_analog_playback
9412#define alc662_pcm_analog_capture alc880_pcm_analog_capture
9413#define alc662_pcm_digital_playback alc880_pcm_digital_playback
9414#define alc662_pcm_digital_capture alc880_pcm_digital_capture
9415
9416/*
9417 * configuration and preset
9418 */
9419static const char *alc662_models[ALC662_MODEL_LAST] = {
9420 [ALC662_3ST_2ch_DIG] = "3stack-dig",
9421 [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
9422 [ALC662_3ST_6ch] = "3stack-6ch",
9423 [ALC662_5ST_DIG] = "6stack-dig",
9424 [ALC662_LENOVO_101E] = "lenovo-101e",
9425 [ALC662_AUTO] = "auto",
9426};
9427
9428static struct snd_pci_quirk alc662_cfg_tbl[] = {
9429 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
9430 {}
9431};
9432
9433static struct alc_config_preset alc662_presets[] = {
9434 [ALC662_3ST_2ch_DIG] = {
9435 .mixers = { alc662_3ST_2ch_mixer },
9436 .init_verbs = { alc662_init_verbs },
9437 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
9438 .dac_nids = alc662_dac_nids,
9439 .dig_out_nid = ALC662_DIGOUT_NID,
9440 .num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
9441 .adc_nids = alc662_adc_nids,
9442 .dig_in_nid = ALC662_DIGIN_NID,
9443 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
9444 .channel_mode = alc662_3ST_2ch_modes,
9445 .input_mux = &alc662_capture_source,
9446 },
9447 [ALC662_3ST_6ch_DIG] = {
9448 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
9449 .init_verbs = { alc662_init_verbs },
9450 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
9451 .dac_nids = alc662_dac_nids,
9452 .dig_out_nid = ALC662_DIGOUT_NID,
9453 .num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
9454 .adc_nids = alc662_adc_nids,
9455 .dig_in_nid = ALC662_DIGIN_NID,
9456 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
9457 .channel_mode = alc662_3ST_6ch_modes,
9458 .need_dac_fix = 1,
9459 .input_mux = &alc662_capture_source,
9460 },
9461 [ALC662_3ST_6ch] = {
9462 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
9463 .init_verbs = { alc662_init_verbs },
9464 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
9465 .dac_nids = alc662_dac_nids,
9466 .num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
9467 .adc_nids = alc662_adc_nids,
9468 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
9469 .channel_mode = alc662_3ST_6ch_modes,
9470 .need_dac_fix = 1,
9471 .input_mux = &alc662_capture_source,
9472 },
9473 [ALC662_5ST_DIG] = {
9474 .mixers = { alc662_base_mixer, alc662_chmode_mixer },
9475 .init_verbs = { alc662_init_verbs },
9476 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
9477 .dac_nids = alc662_dac_nids,
9478 .dig_out_nid = ALC662_DIGOUT_NID,
9479 .num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
9480 .adc_nids = alc662_adc_nids,
9481 .dig_in_nid = ALC662_DIGIN_NID,
9482 .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
9483 .channel_mode = alc662_5stack_modes,
9484 .input_mux = &alc662_capture_source,
9485 },
9486 [ALC662_LENOVO_101E] = {
9487 .mixers = { alc662_lenovo_101e_mixer },
9488 .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
9489 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
9490 .dac_nids = alc662_dac_nids,
9491 .num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
9492 .adc_nids = alc662_adc_nids,
9493 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
9494 .channel_mode = alc662_3ST_2ch_modes,
9495 .input_mux = &alc662_lenovo_101e_capture_source,
9496 .unsol_event = alc662_lenovo_101e_unsol_event,
9497 .init_hook = alc662_lenovo_101e_all_automute,
9498 },
9499
9500};
9501
9502
9503/*
9504 * BIOS auto configuration
9505 */
9506
9507/* add playback controls from the parsed DAC table */
9508static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec,
9509 const struct auto_pin_cfg *cfg)
9510{
9511 char name[32];
9512 static const char *chname[4] = {
9513 "Front", "Surround", NULL /*CLFE*/, "Side"
9514 };
9515 hda_nid_t nid;
9516 int i, err;
9517
9518 for (i = 0; i < cfg->line_outs; i++) {
9519 if (!spec->multiout.dac_nids[i])
9520 continue;
9521 nid = alc880_idx_to_dac(i);
9522 if (i == 2) {
9523 /* Center/LFE */
9524 err = add_control(spec, ALC_CTL_WIDGET_VOL,
9525 "Center Playback Volume",
9526 HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT));
9527 if (err < 0)
9528 return err;
9529 err = add_control(spec, ALC_CTL_WIDGET_VOL,
9530 "LFE Playback Volume",
9531 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT));
9532 if (err < 0)
9533 return err;
9534 err = add_control(spec, ALC_CTL_BIND_MUTE,
9535 "Center Playback Switch",
9536 HDA_COMPOSE_AMP_VAL(nid, 1, 2, HDA_INPUT));
9537 if (err < 0)
9538 return err;
9539 err = add_control(spec, ALC_CTL_BIND_MUTE,
9540 "LFE Playback Switch",
9541 HDA_COMPOSE_AMP_VAL(nid, 2, 2, HDA_INPUT));
9542 if (err < 0)
9543 return err;
9544 } else {
9545 sprintf(name, "%s Playback Volume", chname[i]);
9546 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
9547 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
9548 if (err < 0)
9549 return err;
9550 sprintf(name, "%s Playback Switch", chname[i]);
9551 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
9552 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
9553 if (err < 0)
9554 return err;
9555 }
9556 }
9557 return 0;
9558}
9559
9560/* add playback controls for speaker and HP outputs */
9561static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
9562 const char *pfx)
9563{
9564 hda_nid_t nid;
9565 int err;
9566 char name[32];
9567
9568 if (!pin)
9569 return 0;
9570
9571 if (alc880_is_fixed_pin(pin)) {
9572 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
9573 /* printk("DAC nid=%x\n",nid); */
9574 /* specify the DAC as the extra output */
9575 if (!spec->multiout.hp_nid)
9576 spec->multiout.hp_nid = nid;
9577 else
9578 spec->multiout.extra_out_nid[0] = nid;
9579 /* control HP volume/switch on the output mixer amp */
9580 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
9581 sprintf(name, "%s Playback Volume", pfx);
9582 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
9583 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
9584 if (err < 0)
9585 return err;
9586 sprintf(name, "%s Playback Switch", pfx);
9587 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
9588 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
9589 if (err < 0)
9590 return err;
9591 } else if (alc880_is_multi_pin(pin)) {
9592 /* set manual connection */
9593 /* we have only a switch on HP-out PIN */
9594 sprintf(name, "%s Playback Switch", pfx);
9595 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
9596 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
9597 if (err < 0)
9598 return err;
9599 }
9600 return 0;
9601}
9602
9603/* create playback/capture controls for input pins */
9604static int alc662_auto_create_analog_input_ctls(struct alc_spec *spec,
9605 const struct auto_pin_cfg *cfg)
9606{
9607 struct hda_input_mux *imux = &spec->private_imux;
9608 int i, err, idx;
9609
9610 for (i = 0; i < AUTO_PIN_LAST; i++) {
9611 if (alc880_is_input_pin(cfg->input_pins[i])) {
9612 idx = alc880_input_pin_idx(cfg->input_pins[i]);
9613 err = new_analog_input(spec, cfg->input_pins[i],
9614 auto_pin_cfg_labels[i],
9615 idx, 0x0b);
9616 if (err < 0)
9617 return err;
9618 imux->items[imux->num_items].label =
9619 auto_pin_cfg_labels[i];
9620 imux->items[imux->num_items].index =
9621 alc880_input_pin_idx(cfg->input_pins[i]);
9622 imux->num_items++;
9623 }
9624 }
9625 return 0;
9626}
9627
9628static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
9629 hda_nid_t nid, int pin_type,
9630 int dac_idx)
9631{
9632 /* set as output */
9633 snd_hda_codec_write(codec, nid, 0,
9634 AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
9635 snd_hda_codec_write(codec, nid, 0,
9636 AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
9637 /* need the manual connection? */
9638 if (alc880_is_multi_pin(nid)) {
9639 struct alc_spec *spec = codec->spec;
9640 int idx = alc880_multi_pin_idx(nid);
9641 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
9642 AC_VERB_SET_CONNECT_SEL,
9643 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
9644 }
9645}
9646
9647static void alc662_auto_init_multi_out(struct hda_codec *codec)
9648{
9649 struct alc_spec *spec = codec->spec;
9650 int i;
9651
9652 for (i = 0; i <= HDA_SIDE; i++) {
9653 hda_nid_t nid = spec->autocfg.line_out_pins[i];
9654 if (nid)
9655 alc662_auto_set_output_and_unmute(codec, nid, PIN_OUT,
9656 i);
9657 }
9658}
9659
9660static void alc662_auto_init_hp_out(struct hda_codec *codec)
9661{
9662 struct alc_spec *spec = codec->spec;
9663 hda_nid_t pin;
9664
9665 pin = spec->autocfg.hp_pins[0];
9666 if (pin) /* connect to front */
9667 /* use dac 0 */
9668 alc662_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
9669}
9670
9671#define alc662_is_input_pin(nid) alc880_is_input_pin(nid)
9672#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID
9673
9674static void alc662_auto_init_analog_input(struct hda_codec *codec)
9675{
9676 struct alc_spec *spec = codec->spec;
9677 int i;
9678
9679 for (i = 0; i < AUTO_PIN_LAST; i++) {
9680 hda_nid_t nid = spec->autocfg.input_pins[i];
9681 if (alc662_is_input_pin(nid)) {
9682 snd_hda_codec_write(codec, nid, 0,
9683 AC_VERB_SET_PIN_WIDGET_CONTROL,
9684 (i <= AUTO_PIN_FRONT_MIC ?
9685 PIN_VREF80 : PIN_IN));
9686 if (nid != ALC662_PIN_CD_NID)
9687 snd_hda_codec_write(codec, nid, 0,
9688 AC_VERB_SET_AMP_GAIN_MUTE,
9689 AMP_OUT_MUTE);
9690 }
9691 }
9692}
9693
9694static int alc662_parse_auto_config(struct hda_codec *codec)
9695{
9696 struct alc_spec *spec = codec->spec;
9697 int err;
9698 static hda_nid_t alc662_ignore[] = { 0x1d, 0 };
9699
9700 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
9701 alc662_ignore);
9702 if (err < 0)
9703 return err;
9704 if (!spec->autocfg.line_outs)
9705 return 0; /* can't find valid BIOS pin config */
9706
9707 if ((err = alc880_auto_fill_dac_nids(spec, &spec->autocfg)) < 0 ||
9708 (err = alc662_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 ||
9709 (err = alc662_auto_create_extra_out(spec,
9710 spec->autocfg.speaker_pins[0],
9711 "Speaker")) < 0 ||
9712 (err = alc662_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
9713 "Headphone")) < 0 ||
9714 (err = alc662_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
9715 return err;
9716
9717 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
9718
9719 if (spec->autocfg.dig_out_pin)
9720 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
9721
9722 if (spec->kctl_alloc)
9723 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
9724
9725 spec->num_mux_defs = 1;
9726 spec->input_mux = &spec->private_imux;
9727
9728 if (err < 0)
9729 return err;
9730 else if (err > 0)
9731 /* hack - override the init verbs */
9732 spec->init_verbs[0] = alc662_auto_init_verbs;
9733 spec->mixers[spec->num_mixers] = alc662_capture_mixer;
9734 spec->num_mixers++;
9735 return err;
9736}
9737
9738/* additional initialization for auto-configuration model */
9739static void alc662_auto_init(struct hda_codec *codec)
9740{
9741 alc662_auto_init_multi_out(codec);
9742 alc662_auto_init_hp_out(codec);
9743 alc662_auto_init_analog_input(codec);
9744}
9745
9746static int patch_alc662(struct hda_codec *codec)
9747{
9748 struct alc_spec *spec;
9749 int err, board_config;
9750
9751 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
9752 if (!spec)
9753 return -ENOMEM;
9754
9755 codec->spec = spec;
9756
9757 board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
9758 alc662_models,
9759 alc662_cfg_tbl);
9760 if (board_config < 0) {
9761 printk(KERN_INFO "hda_codec: Unknown model for ALC662, "
9762 "trying auto-probe from BIOS...\n");
9763 board_config = ALC662_AUTO;
9764 }
9765
9766 if (board_config == ALC662_AUTO) {
9767 /* automatic parse from the BIOS config */
9768 err = alc662_parse_auto_config(codec);
9769 if (err < 0) {
9770 alc_free(codec);
9771 return err;
9772 } else if (err) {
9773 printk(KERN_INFO
9774 "hda_codec: Cannot set up configuration "
9775 "from BIOS. Using base mode...\n");
9776 board_config = ALC662_3ST_2ch_DIG;
9777 }
9778 }
9779
9780 if (board_config != ALC662_AUTO)
9781 setup_preset(spec, &alc662_presets[board_config]);
9782
9783 spec->stream_name_analog = "ALC662 Analog";
9784 spec->stream_analog_playback = &alc662_pcm_analog_playback;
9785 spec->stream_analog_capture = &alc662_pcm_analog_capture;
9786
9787 spec->stream_name_digital = "ALC662 Digital";
9788 spec->stream_digital_playback = &alc662_pcm_digital_playback;
9789 spec->stream_digital_capture = &alc662_pcm_digital_capture;
9790
9791 if (!spec->adc_nids && spec->input_mux) {
9792 spec->adc_nids = alc662_adc_nids;
9793 spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
9794 }
9795
9796 codec->patch_ops = alc_patch_ops;
9797 if (board_config == ALC662_AUTO)
9798 spec->init_hook = alc662_auto_init;
9799
9800 return 0;
9801}
9802
9803/*
8692 * patch entries 9804 * patch entries
8693 */ 9805 */
8694struct hda_codec_preset snd_hda_preset_realtek[] = { 9806struct hda_codec_preset snd_hda_preset_realtek[] = {
8695 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 }, 9807 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
8696 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 }, 9808 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
8697 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660", 9809 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
8698 .patch = patch_alc861 }, 9810 .patch = patch_alc861 },
8699 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd }, 9811 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
8700 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 }, 9812 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
8701 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd }, 9813 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
9814 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
9815 .patch = patch_alc883 },
9816 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
9817 .patch = patch_alc662 },
8702 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 }, 9818 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
8703 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 }, 9819 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
8704 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 }, 9820 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 },