diff options
author | Kailang Yang <kailang@realtek.com.tw> | 2005-12-05 13:42:22 -0500 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2006-01-03 06:30:20 -0500 |
commit | df694daa3c0135202e4702cb2d11e68a43f6c51e (patch) | |
tree | 1c274f376771ec0ace88200dc97141702ef42a38 /sound/pci/hda/patch_realtek.c | |
parent | 59acf76e0268e3f0156ef5113e89d838a8c02bb6 (diff) |
[ALSA] hda-codec - Add the support of ALC262,ALC883,ALC885,ALC861
Modules: HDA Codec driver,HDA generic driver
This patch adds the support of ALC262,ALC883,ALC885,ALC861 to driver
More models and improvements for ALC880, ALC260 and ALC882 codecs, too.
Signed-off-by: Kailang Yang <kailang@realtek.com.tw>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda/patch_realtek.c')
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 2367 |
1 files changed, 2177 insertions, 190 deletions
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index c5fb141f6222..a98c0e4da0ac 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -3,7 +3,8 @@ | |||
3 | * | 3 | * |
4 | * HD audio interface patch for ALC 260/880/882 codecs | 4 | * HD audio interface patch for ALC 260/880/882 codecs |
5 | * | 5 | * |
6 | * Copyright (c) 2004 PeiSen Hou <pshou@realtek.com.tw> | 6 | * Copyright (c) 2004 Kailang Yang <kailang@realtek.com.tw> |
7 | * PeiSen Hou <pshou@realtek.com.tw> | ||
7 | * Takashi Iwai <tiwai@suse.de> | 8 | * Takashi Iwai <tiwai@suse.de> |
8 | * | 9 | * |
9 | * This driver is free software; you can redistribute it and/or modify | 10 | * This driver is free software; you can redistribute it and/or modify |
@@ -39,17 +40,20 @@ enum { | |||
39 | ALC880_5ST_DIG, | 40 | ALC880_5ST_DIG, |
40 | ALC880_W810, | 41 | ALC880_W810, |
41 | ALC880_Z71V, | 42 | ALC880_Z71V, |
42 | ALC880_AUTO, | ||
43 | ALC880_6ST, | 43 | ALC880_6ST, |
44 | ALC880_6ST_DIG, | 44 | ALC880_6ST_DIG, |
45 | ALC880_F1734, | 45 | ALC880_F1734, |
46 | ALC880_ASUS, | 46 | ALC880_ASUS, |
47 | ALC880_ASUS_DIG, | 47 | ALC880_ASUS_DIG, |
48 | ALC880_ASUS_W1V, | 48 | ALC880_ASUS_W1V, |
49 | ALC880_ASUS_DIG2, | ||
49 | ALC880_UNIWILL_DIG, | 50 | ALC880_UNIWILL_DIG, |
51 | ALC880_CLEVO, | ||
52 | ALC880_TCL_S700, | ||
50 | #ifdef CONFIG_SND_DEBUG | 53 | #ifdef CONFIG_SND_DEBUG |
51 | ALC880_TEST, | 54 | ALC880_TEST, |
52 | #endif | 55 | #endif |
56 | ALC880_AUTO, | ||
53 | ALC880_MODEL_LAST /* last tag */ | 57 | ALC880_MODEL_LAST /* last tag */ |
54 | }; | 58 | }; |
55 | 59 | ||
@@ -57,16 +61,45 @@ enum { | |||
57 | enum { | 61 | enum { |
58 | ALC260_BASIC, | 62 | ALC260_BASIC, |
59 | ALC260_HP, | 63 | ALC260_HP, |
60 | ALC260_FUJITSU_S702x, | 64 | ALC260_HP_3013, |
65 | ALC260_FUJITSU_S702X, | ||
66 | ALC260_AUTO, | ||
61 | ALC260_MODEL_LAST /* last tag */ | 67 | ALC260_MODEL_LAST /* last tag */ |
62 | }; | 68 | }; |
63 | 69 | ||
70 | /* ALC262 models */ | ||
71 | enum { | ||
72 | ALC262_BASIC, | ||
73 | ALC262_AUTO, | ||
74 | ALC262_MODEL_LAST /* last tag */ | ||
75 | }; | ||
76 | |||
77 | /* ALC861 models */ | ||
78 | enum { | ||
79 | ALC861_3ST, | ||
80 | ALC861_3ST_DIG, | ||
81 | ALC861_6ST_DIG, | ||
82 | ALC861_AUTO, | ||
83 | ALC861_MODEL_LAST, | ||
84 | }; | ||
85 | |||
86 | /* ALC882 models */ | ||
87 | enum { | ||
88 | ALC882_3ST_DIG, | ||
89 | ALC882_6ST_DIG, | ||
90 | ALC882_AUTO, | ||
91 | ALC882_MODEL_LAST, | ||
92 | }; | ||
93 | |||
94 | /* for GPIO Poll */ | ||
95 | #define GPIO_MASK 0x03 | ||
96 | |||
64 | struct alc_spec { | 97 | struct alc_spec { |
65 | /* codec parameterization */ | 98 | /* codec parameterization */ |
66 | struct snd_kcontrol_new *mixers[3]; /* mixer arrays */ | 99 | struct snd_kcontrol_new *mixers[5]; /* mixer arrays */ |
67 | unsigned int num_mixers; | 100 | unsigned int num_mixers; |
68 | 101 | ||
69 | const struct hda_verb *init_verbs[3]; /* initialization verbs | 102 | const struct hda_verb *init_verbs[5]; /* initialization verbs |
70 | * don't forget NULL termination! | 103 | * don't forget NULL termination! |
71 | */ | 104 | */ |
72 | unsigned int num_init_verbs; | 105 | unsigned int num_init_verbs; |
@@ -106,7 +139,25 @@ struct alc_spec { | |||
106 | unsigned int num_kctl_alloc, num_kctl_used; | 139 | unsigned int num_kctl_alloc, num_kctl_used; |
107 | struct snd_kcontrol_new *kctl_alloc; | 140 | struct snd_kcontrol_new *kctl_alloc; |
108 | struct hda_input_mux private_imux; | 141 | struct hda_input_mux private_imux; |
109 | hda_nid_t private_dac_nids[4]; | 142 | hda_nid_t private_dac_nids[5]; |
143 | }; | ||
144 | |||
145 | /* | ||
146 | * configuration template - to be copied to the spec instance | ||
147 | */ | ||
148 | struct alc_config_preset { | ||
149 | struct snd_kcontrol_new *mixers[5]; /* should be identical size with spec */ | ||
150 | const struct hda_verb *init_verbs[5]; | ||
151 | unsigned int num_dacs; | ||
152 | hda_nid_t *dac_nids; | ||
153 | hda_nid_t dig_out_nid; /* optional */ | ||
154 | hda_nid_t hp_nid; /* optional */ | ||
155 | unsigned int num_adc_nids; | ||
156 | hda_nid_t *adc_nids; | ||
157 | hda_nid_t dig_in_nid; | ||
158 | unsigned int num_channel_mode; | ||
159 | const struct hda_channel_mode *channel_mode; | ||
160 | const struct hda_input_mux *input_mux; | ||
110 | }; | 161 | }; |
111 | 162 | ||
112 | 163 | ||
@@ -143,7 +194,7 @@ static int alc_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v | |||
143 | /* | 194 | /* |
144 | * channel mode setting | 195 | * channel mode setting |
145 | */ | 196 | */ |
146 | static int alc880_ch_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 197 | static int alc_ch_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
147 | { | 198 | { |
148 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 199 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
149 | struct alc_spec *spec = codec->spec; | 200 | struct alc_spec *spec = codec->spec; |
@@ -151,7 +202,7 @@ static int alc880_ch_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_ele | |||
151 | spec->num_channel_mode); | 202 | spec->num_channel_mode); |
152 | } | 203 | } |
153 | 204 | ||
154 | static int alc880_ch_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 205 | static int alc_ch_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
155 | { | 206 | { |
156 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 207 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
157 | struct alc_spec *spec = codec->spec; | 208 | struct alc_spec *spec = codec->spec; |
@@ -159,7 +210,7 @@ static int alc880_ch_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem | |||
159 | spec->num_channel_mode, spec->multiout.max_channels); | 210 | spec->num_channel_mode, spec->multiout.max_channels); |
160 | } | 211 | } |
161 | 212 | ||
162 | static int alc880_ch_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 213 | static int alc_ch_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
163 | { | 214 | { |
164 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 215 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
165 | struct alc_spec *spec = codec->spec; | 216 | struct alc_spec *spec = codec->spec; |
@@ -217,6 +268,36 @@ static int alc_pinctl_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
217 | .put = alc_pinctl_switch_put, \ | 268 | .put = alc_pinctl_switch_put, \ |
218 | .private_value = (nid) | (mask<<16) } | 269 | .private_value = (nid) | (mask<<16) } |
219 | 270 | ||
271 | |||
272 | /* | ||
273 | * set up from the preset table | ||
274 | */ | ||
275 | static void setup_preset(struct alc_spec *spec, const struct alc_config_preset *preset) | ||
276 | { | ||
277 | int i; | ||
278 | |||
279 | for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++) | ||
280 | spec->mixers[spec->num_mixers++] = preset->mixers[i]; | ||
281 | for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i]; i++) | ||
282 | spec->init_verbs[spec->num_init_verbs++] = preset->init_verbs[i]; | ||
283 | |||
284 | spec->channel_mode = preset->channel_mode; | ||
285 | spec->num_channel_mode = preset->num_channel_mode; | ||
286 | |||
287 | spec->multiout.max_channels = spec->channel_mode[0].channels; | ||
288 | |||
289 | spec->multiout.num_dacs = preset->num_dacs; | ||
290 | spec->multiout.dac_nids = preset->dac_nids; | ||
291 | spec->multiout.dig_out_nid = preset->dig_out_nid; | ||
292 | spec->multiout.hp_nid = preset->hp_nid; | ||
293 | |||
294 | spec->input_mux = preset->input_mux; | ||
295 | |||
296 | spec->num_adc_nids = preset->num_adc_nids; | ||
297 | spec->adc_nids = preset->adc_nids; | ||
298 | spec->dig_in_nid = preset->dig_in_nid; | ||
299 | } | ||
300 | |||
220 | /* | 301 | /* |
221 | * ALC880 3-stack model | 302 | * ALC880 3-stack model |
222 | * | 303 | * |
@@ -237,6 +318,7 @@ static hda_nid_t alc880_adc_nids[3] = { | |||
237 | 318 | ||
238 | /* The datasheet says the node 0x07 is connected from inputs, | 319 | /* The datasheet says the node 0x07 is connected from inputs, |
239 | * but it shows zero connection in the real implementation on some devices. | 320 | * but it shows zero connection in the real implementation on some devices. |
321 | * Note: this is a 915GAV bug, fixed on 915GLV | ||
240 | */ | 322 | */ |
241 | static hda_nid_t alc880_adc_nids_alt[2] = { | 323 | static hda_nid_t alc880_adc_nids_alt[2] = { |
242 | /* ADC1-2 */ | 324 | /* ADC1-2 */ |
@@ -307,9 +389,9 @@ static struct snd_kcontrol_new alc880_three_stack_mixer[] = { | |||
307 | { | 389 | { |
308 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 390 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
309 | .name = "Channel Mode", | 391 | .name = "Channel Mode", |
310 | .info = alc880_ch_mode_info, | 392 | .info = alc_ch_mode_info, |
311 | .get = alc880_ch_mode_get, | 393 | .get = alc_ch_mode_get, |
312 | .put = alc880_ch_mode_put, | 394 | .put = alc_ch_mode_put, |
313 | }, | 395 | }, |
314 | { } /* end */ | 396 | { } /* end */ |
315 | }; | 397 | }; |
@@ -452,9 +534,9 @@ static struct snd_kcontrol_new alc880_six_stack_mixer[] = { | |||
452 | { | 534 | { |
453 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 535 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
454 | .name = "Channel Mode", | 536 | .name = "Channel Mode", |
455 | .info = alc880_ch_mode_info, | 537 | .info = alc_ch_mode_info, |
456 | .get = alc880_ch_mode_get, | 538 | .get = alc_ch_mode_get, |
457 | .put = alc880_ch_mode_put, | 539 | .put = alc_ch_mode_put, |
458 | }, | 540 | }, |
459 | { } /* end */ | 541 | { } /* end */ |
460 | }; | 542 | }; |
@@ -596,9 +678,9 @@ static struct snd_kcontrol_new alc880_asus_mixer[] = { | |||
596 | { | 678 | { |
597 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 679 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
598 | .name = "Channel Mode", | 680 | .name = "Channel Mode", |
599 | .info = alc880_ch_mode_info, | 681 | .info = alc_ch_mode_info, |
600 | .get = alc880_ch_mode_get, | 682 | .get = alc_ch_mode_get, |
601 | .put = alc880_ch_mode_put, | 683 | .put = alc_ch_mode_put, |
602 | }, | 684 | }, |
603 | { } /* end */ | 685 | { } /* end */ |
604 | }; | 686 | }; |
@@ -626,6 +708,33 @@ static struct snd_kcontrol_new alc880_pcbeep_mixer[] = { | |||
626 | { } /* end */ | 708 | { } /* end */ |
627 | }; | 709 | }; |
628 | 710 | ||
711 | /* TCL S700 */ | ||
712 | static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = { | ||
713 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
714 | HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | ||
715 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), | ||
716 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT), | ||
717 | HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT), | ||
718 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT), | ||
719 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT), | ||
720 | HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), | ||
721 | HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), | ||
722 | { | ||
723 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
724 | /* The multiple "Capture Source" controls confuse alsamixer | ||
725 | * So call somewhat different.. | ||
726 | * FIXME: the controls appear in the "playback" view! | ||
727 | */ | ||
728 | /* .name = "Capture Source", */ | ||
729 | .name = "Input Source", | ||
730 | .count = 1, | ||
731 | .info = alc_mux_enum_info, | ||
732 | .get = alc_mux_enum_get, | ||
733 | .put = alc_mux_enum_put, | ||
734 | }, | ||
735 | { } /* end */ | ||
736 | }; | ||
737 | |||
629 | /* | 738 | /* |
630 | * build control elements | 739 | * build control elements |
631 | */ | 740 | */ |
@@ -925,6 +1034,8 @@ static struct hda_verb alc880_gpio1_init_verbs[] = { | |||
925 | {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, | 1034 | {0x01, AC_VERB_SET_GPIO_MASK, 0x01}, |
926 | {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, | 1035 | {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, |
927 | {0x01, AC_VERB_SET_GPIO_DATA, 0x01}, | 1036 | {0x01, AC_VERB_SET_GPIO_DATA, 0x01}, |
1037 | |||
1038 | { } | ||
928 | }; | 1039 | }; |
929 | 1040 | ||
930 | /* Enable GPIO mask and set output */ | 1041 | /* Enable GPIO mask and set output */ |
@@ -932,8 +1043,59 @@ static struct hda_verb alc880_gpio2_init_verbs[] = { | |||
932 | {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, | 1043 | {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, |
933 | {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, | 1044 | {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, |
934 | {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, | 1045 | {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, |
1046 | |||
1047 | { } | ||
935 | }; | 1048 | }; |
936 | 1049 | ||
1050 | /* Clevo m520g init */ | ||
1051 | static struct hda_verb alc880_pin_clevo_init_verbs[] = { | ||
1052 | /* headphone output */ | ||
1053 | {0x11, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
1054 | /* line-out */ | ||
1055 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
1056 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1057 | /* Line-in */ | ||
1058 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
1059 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1060 | /* CD */ | ||
1061 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
1062 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1063 | /* Mic1 (rear panel) */ | ||
1064 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
1065 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1066 | /* Mic2 (front panel) */ | ||
1067 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
1068 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1069 | /* headphone */ | ||
1070 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
1071 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1072 | /* change to EAPD mode */ | ||
1073 | {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, | ||
1074 | {0x20, AC_VERB_SET_PROC_COEF, 0x3060}, | ||
1075 | |||
1076 | { } | ||
1077 | }; | ||
1078 | |||
1079 | static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = { | ||
1080 | /* Headphone output */ | ||
1081 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
1082 | /* Front output*/ | ||
1083 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
1084 | {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
1085 | |||
1086 | /* Line In pin widget for input */ | ||
1087 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
1088 | /* CD pin widget for input */ | ||
1089 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
1090 | /* Mic1 (rear panel) pin widget for input and vref at 80% */ | ||
1091 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
1092 | |||
1093 | /* change to EAPD mode */ | ||
1094 | {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, | ||
1095 | {0x20, AC_VERB_SET_PROC_COEF, 0x3070}, | ||
1096 | |||
1097 | { } | ||
1098 | }; | ||
937 | 1099 | ||
938 | /* | 1100 | /* |
939 | */ | 1101 | */ |
@@ -1344,9 +1506,9 @@ static struct snd_kcontrol_new alc880_test_mixer[] = { | |||
1344 | { | 1506 | { |
1345 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1507 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1346 | .name = "Channel Mode", | 1508 | .name = "Channel Mode", |
1347 | .info = alc880_ch_mode_info, | 1509 | .info = alc_ch_mode_info, |
1348 | .get = alc880_ch_mode_get, | 1510 | .get = alc_ch_mode_get, |
1349 | .put = alc880_ch_mode_put, | 1511 | .put = alc_ch_mode_put, |
1350 | }, | 1512 | }, |
1351 | { } /* end */ | 1513 | { } /* end */ |
1352 | }; | 1514 | }; |
@@ -1442,6 +1604,8 @@ static struct hda_board_config alc880_cfg_tbl[] = { | |||
1442 | { .pci_subvendor = 0x107b, .pci_subdevice = 0x4038, .config = ALC880_3ST }, | 1604 | { .pci_subvendor = 0x107b, .pci_subdevice = 0x4038, .config = ALC880_3ST }, |
1443 | { .pci_subvendor = 0x107b, .pci_subdevice = 0x4040, .config = ALC880_3ST }, | 1605 | { .pci_subvendor = 0x107b, .pci_subdevice = 0x4040, .config = ALC880_3ST }, |
1444 | { .pci_subvendor = 0x107b, .pci_subdevice = 0x4041, .config = ALC880_3ST }, | 1606 | { .pci_subvendor = 0x107b, .pci_subdevice = 0x4041, .config = ALC880_3ST }, |
1607 | /* TCL S700 */ | ||
1608 | { .pci_subvendor = 0x19db, .pci_subdevice = 0x4188, .config = ALC880_TCL_S700 }, | ||
1445 | 1609 | ||
1446 | /* Back 3 jack, front 2 jack (Internal add Aux-In) */ | 1610 | /* Back 3 jack, front 2 jack (Internal add Aux-In) */ |
1447 | { .pci_subvendor = 0x1025, .pci_subdevice = 0xe310, .config = ALC880_3ST }, | 1611 | { .pci_subvendor = 0x1025, .pci_subdevice = 0xe310, .config = ALC880_3ST }, |
@@ -1452,6 +1616,8 @@ static struct hda_board_config alc880_cfg_tbl[] = { | |||
1452 | { .modelname = "3stack-digout", .config = ALC880_3ST_DIG }, | 1616 | { .modelname = "3stack-digout", .config = ALC880_3ST_DIG }, |
1453 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe308, .config = ALC880_3ST_DIG }, | 1617 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe308, .config = ALC880_3ST_DIG }, |
1454 | { .pci_subvendor = 0x1025, .pci_subdevice = 0x0070, .config = ALC880_3ST_DIG }, | 1618 | { .pci_subvendor = 0x1025, .pci_subdevice = 0x0070, .config = ALC880_3ST_DIG }, |
1619 | /* Clevo m520G NB */ | ||
1620 | { .pci_subvendor = 0x1558, .pci_subdevice = 0x0520, .config = ALC880_CLEVO }, | ||
1455 | 1621 | ||
1456 | /* Back 3 jack plus 1 SPDIF out jack, front 2 jack (Internal add Aux-In)*/ | 1622 | /* Back 3 jack plus 1 SPDIF out jack, front 2 jack (Internal add Aux-In)*/ |
1457 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe305, .config = ALC880_3ST_DIG }, | 1623 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe305, .config = ALC880_3ST_DIG }, |
@@ -1489,6 +1655,7 @@ static struct hda_board_config alc880_cfg_tbl[] = { | |||
1489 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_Z71V }, | 1655 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_Z71V }, |
1490 | 1656 | ||
1491 | { .modelname = "6stack", .config = ALC880_6ST }, | 1657 | { .modelname = "6stack", .config = ALC880_6ST }, |
1658 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x81b4, .config = ALC880_6ST }, | ||
1492 | { .pci_subvendor = 0x1019, .pci_subdevice = 0xa884, .config = ALC880_6ST }, /* Acer APFV */ | 1659 | { .pci_subvendor = 0x1019, .pci_subdevice = 0xa884, .config = ALC880_6ST }, /* Acer APFV */ |
1493 | 1660 | ||
1494 | { .modelname = "6stack-digout", .config = ALC880_6ST_DIG }, | 1661 | { .modelname = "6stack-digout", .config = ALC880_6ST_DIG }, |
@@ -1496,6 +1663,10 @@ static struct hda_board_config alc880_cfg_tbl[] = { | |||
1496 | { .pci_subvendor = 0x8086, .pci_subdevice = 0x2668, .config = ALC880_6ST_DIG }, | 1663 | { .pci_subvendor = 0x8086, .pci_subdevice = 0x2668, .config = ALC880_6ST_DIG }, |
1497 | { .pci_subvendor = 0x1462, .pci_subdevice = 0x1150, .config = ALC880_6ST_DIG }, | 1664 | { .pci_subvendor = 0x1462, .pci_subdevice = 0x1150, .config = ALC880_6ST_DIG }, |
1498 | { .pci_subvendor = 0xe803, .pci_subdevice = 0x1019, .config = ALC880_6ST_DIG }, | 1665 | { .pci_subvendor = 0xe803, .pci_subdevice = 0x1019, .config = ALC880_6ST_DIG }, |
1666 | { .pci_subvendor = 0x1039, .pci_subdevice = 0x1234, .config = ALC880_6ST_DIG }, | ||
1667 | { .pci_subvendor = 0x1025, .pci_subdevice = 0x0077, .config = ALC880_6ST_DIG }, | ||
1668 | { .pci_subvendor = 0x1025, .pci_subdevice = 0x0078, .config = ALC880_6ST_DIG }, | ||
1669 | { .pci_subvendor = 0x1025, .pci_subdevice = 0x0087, .config = ALC880_6ST_DIG }, | ||
1499 | 1670 | ||
1500 | { .modelname = "asus", .config = ALC880_ASUS }, | 1671 | { .modelname = "asus", .config = ALC880_ASUS }, |
1501 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_ASUS_DIG }, | 1672 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_ASUS_DIG }, |
@@ -1509,37 +1680,26 @@ static struct hda_board_config alc880_cfg_tbl[] = { | |||
1509 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1123, .config = ALC880_ASUS_DIG }, | 1680 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1123, .config = ALC880_ASUS_DIG }, |
1510 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1143, .config = ALC880_ASUS }, | 1681 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1143, .config = ALC880_ASUS }, |
1511 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x10b3, .config = ALC880_ASUS_W1V }, | 1682 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x10b3, .config = ALC880_ASUS_W1V }, |
1683 | { .pci_subvendor = 0x1558, .pci_subdevice = 0x5401, .config = ALC880_ASUS_DIG2 }, | ||
1512 | 1684 | ||
1513 | { .modelname = "uniwill", .config = ALC880_UNIWILL_DIG }, | 1685 | { .modelname = "uniwill", .config = ALC880_UNIWILL_DIG }, |
1514 | { .pci_subvendor = 0x1584, .pci_subdevice = 0x9050, .config = ALC880_UNIWILL_DIG }, | 1686 | { .pci_subvendor = 0x1584, .pci_subdevice = 0x9050, .config = ALC880_UNIWILL_DIG }, |
1515 | 1687 | ||
1516 | { .modelname = "F1734", .config = ALC880_F1734 }, | 1688 | { .modelname = "F1734", .config = ALC880_F1734 }, |
1517 | { .pci_subvendor = 0x1734, .pci_subdevice = 0x107c, .config = ALC880_F1734 }, | 1689 | { .pci_subvendor = 0x1734, .pci_subdevice = 0x107c, .config = ALC880_F1734 }, |
1690 | { .pci_subvendor = 0x1584, .pci_subdevice = 0x9054, .config = ALC880_F1734 }, | ||
1518 | 1691 | ||
1519 | #ifdef CONFIG_SND_DEBUG | 1692 | #ifdef CONFIG_SND_DEBUG |
1520 | { .modelname = "test", .config = ALC880_TEST }, | 1693 | { .modelname = "test", .config = ALC880_TEST }, |
1521 | #endif | 1694 | #endif |
1695 | { .modelname = "auto", .config = ALC880_AUTO }, | ||
1522 | 1696 | ||
1523 | {} | 1697 | {} |
1524 | }; | 1698 | }; |
1525 | 1699 | ||
1526 | /* | 1700 | /* |
1527 | * configuration template - to be copied to the spec instance | 1701 | * ALC880 codec presets |
1528 | */ | 1702 | */ |
1529 | struct alc_config_preset { | ||
1530 | struct snd_kcontrol_new *mixers[4]; | ||
1531 | const struct hda_verb *init_verbs[4]; | ||
1532 | unsigned int num_dacs; | ||
1533 | hda_nid_t *dac_nids; | ||
1534 | hda_nid_t dig_out_nid; /* optional */ | ||
1535 | hda_nid_t hp_nid; /* optional */ | ||
1536 | unsigned int num_adc_nids; | ||
1537 | hda_nid_t *adc_nids; | ||
1538 | unsigned int num_channel_mode; | ||
1539 | const struct hda_channel_mode *channel_mode; | ||
1540 | const struct hda_input_mux *input_mux; | ||
1541 | }; | ||
1542 | |||
1543 | static struct alc_config_preset alc880_presets[] = { | 1703 | static struct alc_config_preset alc880_presets[] = { |
1544 | [ALC880_3ST] = { | 1704 | [ALC880_3ST] = { |
1545 | .mixers = { alc880_three_stack_mixer }, | 1705 | .mixers = { alc880_three_stack_mixer }, |
@@ -1560,6 +1720,18 @@ static struct alc_config_preset alc880_presets[] = { | |||
1560 | .channel_mode = alc880_threestack_modes, | 1720 | .channel_mode = alc880_threestack_modes, |
1561 | .input_mux = &alc880_capture_source, | 1721 | .input_mux = &alc880_capture_source, |
1562 | }, | 1722 | }, |
1723 | [ALC880_TCL_S700] = { | ||
1724 | .mixers = { alc880_tcl_s700_mixer }, | ||
1725 | .init_verbs = { alc880_volume_init_verbs, | ||
1726 | alc880_pin_tcl_S700_init_verbs, | ||
1727 | alc880_gpio2_init_verbs }, | ||
1728 | .num_dacs = ARRAY_SIZE(alc880_dac_nids), | ||
1729 | .dac_nids = alc880_dac_nids, | ||
1730 | .hp_nid = 0x03, | ||
1731 | .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), | ||
1732 | .channel_mode = alc880_2_jack_modes, | ||
1733 | .input_mux = &alc880_capture_source, | ||
1734 | }, | ||
1563 | [ALC880_5ST] = { | 1735 | [ALC880_5ST] = { |
1564 | .mixers = { alc880_three_stack_mixer, alc880_five_stack_mixer}, | 1736 | .mixers = { alc880_three_stack_mixer, alc880_five_stack_mixer}, |
1565 | .init_verbs = { alc880_volume_init_verbs, alc880_pin_5stack_init_verbs }, | 1737 | .init_verbs = { alc880_volume_init_verbs, alc880_pin_5stack_init_verbs }, |
@@ -1651,6 +1823,17 @@ static struct alc_config_preset alc880_presets[] = { | |||
1651 | .channel_mode = alc880_asus_modes, | 1823 | .channel_mode = alc880_asus_modes, |
1652 | .input_mux = &alc880_capture_source, | 1824 | .input_mux = &alc880_capture_source, |
1653 | }, | 1825 | }, |
1826 | [ALC880_ASUS_DIG2] = { | ||
1827 | .mixers = { alc880_asus_mixer }, | ||
1828 | .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs, | ||
1829 | alc880_gpio2_init_verbs }, /* use GPIO2 */ | ||
1830 | .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids), | ||
1831 | .dac_nids = alc880_asus_dac_nids, | ||
1832 | .dig_out_nid = ALC880_DIGOUT_NID, | ||
1833 | .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), | ||
1834 | .channel_mode = alc880_asus_modes, | ||
1835 | .input_mux = &alc880_capture_source, | ||
1836 | }, | ||
1654 | [ALC880_ASUS_W1V] = { | 1837 | [ALC880_ASUS_W1V] = { |
1655 | .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer }, | 1838 | .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer }, |
1656 | .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs, | 1839 | .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs, |
@@ -1672,6 +1855,17 @@ static struct alc_config_preset alc880_presets[] = { | |||
1672 | .channel_mode = alc880_asus_modes, | 1855 | .channel_mode = alc880_asus_modes, |
1673 | .input_mux = &alc880_capture_source, | 1856 | .input_mux = &alc880_capture_source, |
1674 | }, | 1857 | }, |
1858 | [ALC880_CLEVO] = { | ||
1859 | .mixers = { alc880_three_stack_mixer }, | ||
1860 | .init_verbs = { alc880_volume_init_verbs, | ||
1861 | alc880_pin_clevo_init_verbs }, | ||
1862 | .num_dacs = ARRAY_SIZE(alc880_dac_nids), | ||
1863 | .dac_nids = alc880_dac_nids, | ||
1864 | .hp_nid = 0x03, | ||
1865 | .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), | ||
1866 | .channel_mode = alc880_threestack_modes, | ||
1867 | .input_mux = &alc880_capture_source, | ||
1868 | }, | ||
1675 | #ifdef CONFIG_SND_DEBUG | 1869 | #ifdef CONFIG_SND_DEBUG |
1676 | [ALC880_TEST] = { | 1870 | [ALC880_TEST] = { |
1677 | .mixers = { alc880_test_mixer }, | 1871 | .mixers = { alc880_test_mixer }, |
@@ -1783,7 +1977,8 @@ static int alc880_auto_fill_dac_nids(struct alc_spec *spec, const struct auto_pi | |||
1783 | } | 1977 | } |
1784 | 1978 | ||
1785 | /* add playback controls from the parsed DAC table */ | 1979 | /* add playback controls from the parsed DAC table */ |
1786 | static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg) | 1980 | static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec, |
1981 | const struct auto_pin_cfg *cfg) | ||
1787 | { | 1982 | { |
1788 | char name[32]; | 1983 | char name[32]; |
1789 | static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" }; | 1984 | static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" }; |
@@ -1871,35 +2066,38 @@ static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin, | |||
1871 | } | 2066 | } |
1872 | 2067 | ||
1873 | /* create input playback/capture controls for the given pin */ | 2068 | /* create input playback/capture controls for the given pin */ |
1874 | static int new_analog_input(struct alc_spec *spec, hda_nid_t pin, const char *ctlname) | 2069 | static int new_analog_input(struct alc_spec *spec, hda_nid_t pin, const char *ctlname, |
2070 | int idx, hda_nid_t mix_nid) | ||
1875 | { | 2071 | { |
1876 | char name[32]; | 2072 | char name[32]; |
1877 | int err, idx; | 2073 | int err; |
1878 | 2074 | ||
1879 | sprintf(name, "%s Playback Volume", ctlname); | 2075 | sprintf(name, "%s Playback Volume", ctlname); |
1880 | idx = alc880_input_pin_idx(pin); | ||
1881 | if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name, | 2076 | if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name, |
1882 | HDA_COMPOSE_AMP_VAL(0x0b, 3, idx, HDA_INPUT))) < 0) | 2077 | HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT))) < 0) |
1883 | return err; | 2078 | return err; |
1884 | sprintf(name, "%s Playback Switch", ctlname); | 2079 | sprintf(name, "%s Playback Switch", ctlname); |
1885 | if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, | 2080 | if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, |
1886 | HDA_COMPOSE_AMP_VAL(0x0b, 3, idx, HDA_INPUT))) < 0) | 2081 | HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT))) < 0) |
1887 | return err; | 2082 | return err; |
1888 | return 0; | 2083 | return 0; |
1889 | } | 2084 | } |
1890 | 2085 | ||
1891 | /* create playback/capture controls for input pins */ | 2086 | /* create playback/capture controls for input pins */ |
1892 | static int alc880_auto_create_analog_input_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg) | 2087 | static int alc880_auto_create_analog_input_ctls(struct alc_spec *spec, |
2088 | const struct auto_pin_cfg *cfg) | ||
1893 | { | 2089 | { |
1894 | static char *labels[AUTO_PIN_LAST] = { | 2090 | static char *labels[AUTO_PIN_LAST] = { |
1895 | "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux" | 2091 | "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux" |
1896 | }; | 2092 | }; |
1897 | struct hda_input_mux *imux = &spec->private_imux; | 2093 | struct hda_input_mux *imux = &spec->private_imux; |
1898 | int i, err; | 2094 | int i, err, idx; |
1899 | 2095 | ||
1900 | for (i = 0; i < AUTO_PIN_LAST; i++) { | 2096 | for (i = 0; i < AUTO_PIN_LAST; i++) { |
1901 | if (alc880_is_input_pin(cfg->input_pins[i])) { | 2097 | if (alc880_is_input_pin(cfg->input_pins[i])) { |
1902 | err = new_analog_input(spec, cfg->input_pins[i], labels[i]); | 2098 | idx = alc880_input_pin_idx(cfg->input_pins[i]); |
2099 | err = new_analog_input(spec, cfg->input_pins[i], labels[i], | ||
2100 | idx, 0x0b); | ||
1903 | if (err < 0) | 2101 | if (err < 0) |
1904 | return err; | 2102 | return err; |
1905 | imux->items[imux->num_items].label = labels[i]; | 2103 | imux->items[imux->num_items].label = labels[i]; |
@@ -1910,7 +2108,8 @@ static int alc880_auto_create_analog_input_ctls(struct alc_spec *spec, const str | |||
1910 | return 0; | 2108 | return 0; |
1911 | } | 2109 | } |
1912 | 2110 | ||
1913 | static void alc880_auto_set_output_and_unmute(struct hda_codec *codec, hda_nid_t nid, int pin_type, | 2111 | static void alc880_auto_set_output_and_unmute(struct hda_codec *codec, |
2112 | hda_nid_t nid, int pin_type, | ||
1914 | int dac_idx) | 2113 | int dac_idx) |
1915 | { | 2114 | { |
1916 | /* set as output */ | 2115 | /* set as output */ |
@@ -1973,15 +2172,17 @@ static int alc880_parse_auto_config(struct hda_codec *codec) | |||
1973 | { | 2172 | { |
1974 | struct alc_spec *spec = codec->spec; | 2173 | struct alc_spec *spec = codec->spec; |
1975 | int err; | 2174 | int err; |
2175 | static hda_nid_t alc880_ignore[] = { 0x1d, 0 }; | ||
1976 | 2176 | ||
1977 | if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg)) < 0) | 2177 | if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, |
1978 | return err; | 2178 | alc880_ignore)) < 0) |
1979 | if ((err = alc880_auto_fill_dac_nids(spec, &spec->autocfg)) < 0) | ||
1980 | return err; | 2179 | return err; |
1981 | if (! spec->autocfg.line_outs && ! spec->autocfg.speaker_pin && | 2180 | if (! spec->autocfg.line_outs && ! spec->autocfg.speaker_pin && |
1982 | ! spec->autocfg.hp_pin) | 2181 | ! spec->autocfg.hp_pin) |
1983 | return 0; /* can't find valid BIOS pin config */ | 2182 | return 0; /* can't find valid BIOS pin config */ |
1984 | if ((err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 || | 2183 | |
2184 | if ((err = alc880_auto_fill_dac_nids(spec, &spec->autocfg)) < 0 || | ||
2185 | (err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 || | ||
1985 | (err = alc880_auto_create_extra_out(spec, spec->autocfg.speaker_pin, | 2186 | (err = alc880_auto_create_extra_out(spec, spec->autocfg.speaker_pin, |
1986 | "Speaker")) < 0 || | 2187 | "Speaker")) < 0 || |
1987 | (err = alc880_auto_create_extra_out(spec, spec->autocfg.speaker_pin, | 2188 | (err = alc880_auto_create_extra_out(spec, spec->autocfg.speaker_pin, |
@@ -2024,7 +2225,7 @@ static int patch_alc880(struct hda_codec *codec) | |||
2024 | { | 2225 | { |
2025 | struct alc_spec *spec; | 2226 | struct alc_spec *spec; |
2026 | int board_config; | 2227 | int board_config; |
2027 | int i, err; | 2228 | int err; |
2028 | 2229 | ||
2029 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 2230 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
2030 | if (spec == NULL) | 2231 | if (spec == NULL) |
@@ -2050,36 +2251,8 @@ static int patch_alc880(struct hda_codec *codec) | |||
2050 | } | 2251 | } |
2051 | } | 2252 | } |
2052 | 2253 | ||
2053 | if (board_config != ALC880_AUTO) { | 2254 | if (board_config != ALC880_AUTO) |
2054 | /* set up from the preset table */ | 2255 | setup_preset(spec, &alc880_presets[board_config]); |
2055 | const struct alc_config_preset *preset; | ||
2056 | |||
2057 | preset = &alc880_presets[board_config]; | ||
2058 | |||
2059 | for (i = 0; preset->mixers[i]; i++) { | ||
2060 | snd_assert(spec->num_mixers < ARRAY_SIZE(spec->mixers), break); | ||
2061 | spec->mixers[spec->num_mixers++] = preset->mixers[i]; | ||
2062 | } | ||
2063 | for (i = 0; preset->init_verbs[i]; i++) { | ||
2064 | snd_assert(spec->num_init_verbs < ARRAY_SIZE(spec->init_verbs), break); | ||
2065 | spec->init_verbs[spec->num_init_verbs++] = preset->init_verbs[i]; | ||
2066 | } | ||
2067 | |||
2068 | spec->channel_mode = preset->channel_mode; | ||
2069 | spec->num_channel_mode = preset->num_channel_mode; | ||
2070 | |||
2071 | spec->multiout.max_channels = spec->channel_mode[0].channels; | ||
2072 | |||
2073 | spec->multiout.num_dacs = preset->num_dacs; | ||
2074 | spec->multiout.dac_nids = preset->dac_nids; | ||
2075 | spec->multiout.dig_out_nid = preset->dig_out_nid; | ||
2076 | spec->multiout.hp_nid = preset->hp_nid; | ||
2077 | |||
2078 | spec->input_mux = preset->input_mux; | ||
2079 | |||
2080 | spec->num_adc_nids = preset->num_adc_nids; | ||
2081 | spec->adc_nids = preset->adc_nids; | ||
2082 | } | ||
2083 | 2256 | ||
2084 | spec->stream_name_analog = "ALC880 Analog"; | 2257 | spec->stream_name_analog = "ALC880 Analog"; |
2085 | spec->stream_analog_playback = &alc880_pcm_analog_playback; | 2258 | spec->stream_analog_playback = &alc880_pcm_analog_playback; |
@@ -2128,11 +2301,16 @@ static hda_nid_t alc260_adc_nids[1] = { | |||
2128 | 0x04, | 2301 | 0x04, |
2129 | }; | 2302 | }; |
2130 | 2303 | ||
2131 | static hda_nid_t alc260_hp_adc_nids[1] = { | 2304 | static hda_nid_t alc260_adc_nids_alt[1] = { |
2132 | /* ADC1 */ | 2305 | /* ADC1 */ |
2133 | 0x05, | 2306 | 0x05, |
2134 | }; | 2307 | }; |
2135 | 2308 | ||
2309 | static hda_nid_t alc260_hp_adc_nids[2] = { | ||
2310 | /* ADC1, 0 */ | ||
2311 | 0x05, 0x04 | ||
2312 | }; | ||
2313 | |||
2136 | #define ALC260_DIGOUT_NID 0x03 | 2314 | #define ALC260_DIGOUT_NID 0x03 |
2137 | #define ALC260_DIGIN_NID 0x06 | 2315 | #define ALC260_DIGIN_NID 0x06 |
2138 | 2316 | ||
@@ -2167,38 +2345,26 @@ static struct hda_channel_mode alc260_modes[1] = { | |||
2167 | { 2, NULL }, | 2345 | { 2, NULL }, |
2168 | }; | 2346 | }; |
2169 | 2347 | ||
2170 | static struct snd_kcontrol_new alc260_base_mixer[] = { | 2348 | |
2349 | /* Mixer combinations | ||
2350 | * | ||
2351 | * basic: base_output + input + pc_beep + capture | ||
2352 | * HP: base_output + input + capture_alt | ||
2353 | * HP_3013: hp_3013 + input + capture | ||
2354 | * fujitsu: fujitsu + capture | ||
2355 | */ | ||
2356 | |||
2357 | static struct snd_kcontrol_new alc260_base_output_mixer[] = { | ||
2171 | HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), | 2358 | HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), |
2172 | HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), | 2359 | HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), |
2173 | HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), | ||
2174 | HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), | ||
2175 | HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), | ||
2176 | HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), | ||
2177 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), | ||
2178 | HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), | ||
2179 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT), | ||
2180 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT), | ||
2181 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x07, 0x05, HDA_INPUT), | ||
2182 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x07, 0x05, HDA_INPUT), | ||
2183 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT), | 2360 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT), |
2184 | HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT), | 2361 | HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT), |
2185 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), | 2362 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), |
2186 | HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT), | 2363 | HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT), |
2187 | HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT), | ||
2188 | HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT), | ||
2189 | { | ||
2190 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2191 | .name = "Capture Source", | ||
2192 | .info = alc_mux_enum_info, | ||
2193 | .get = alc_mux_enum_get, | ||
2194 | .put = alc_mux_enum_put, | ||
2195 | }, | ||
2196 | { } /* end */ | 2364 | { } /* end */ |
2197 | }; | 2365 | }; |
2198 | 2366 | ||
2199 | static struct snd_kcontrol_new alc260_hp_mixer[] = { | 2367 | static struct snd_kcontrol_new alc260_input_mixer[] = { |
2200 | HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), | ||
2201 | HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), | ||
2202 | HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), | 2368 | HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), |
2203 | HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), | 2369 | HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), |
2204 | HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), | 2370 | HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), |
@@ -2207,19 +2373,24 @@ static struct snd_kcontrol_new alc260_hp_mixer[] = { | |||
2207 | HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), | 2373 | HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), |
2208 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT), | 2374 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT), |
2209 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT), | 2375 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT), |
2210 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT), | 2376 | { } /* end */ |
2211 | HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT), | 2377 | }; |
2212 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), | 2378 | |
2213 | HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT), | 2379 | static struct snd_kcontrol_new alc260_pc_beep_mixer[] = { |
2214 | HDA_CODEC_VOLUME("Capture Volume", 0x05, 0x0, HDA_INPUT), | 2380 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x07, 0x05, HDA_INPUT), |
2215 | HDA_CODEC_MUTE("Capture Switch", 0x05, 0x0, HDA_INPUT), | 2381 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x07, 0x05, HDA_INPUT), |
2216 | { | 2382 | { } /* end */ |
2217 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2383 | }; |
2218 | .name = "Capture Source", | 2384 | |
2219 | .info = alc_mux_enum_info, | 2385 | static struct snd_kcontrol_new alc260_hp_3013_mixer[] = { |
2220 | .get = alc_mux_enum_get, | 2386 | HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT), |
2221 | .put = alc_mux_enum_put, | 2387 | HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT), |
2222 | }, | 2388 | HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT), |
2389 | HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT), | ||
2390 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT), | ||
2391 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
2392 | HDA_CODEC_VOLUME_MONO("iSpeaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), | ||
2393 | HDA_CODEC_MUTE_MONO("iSpeaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT), | ||
2223 | { } /* end */ | 2394 | { } /* end */ |
2224 | }; | 2395 | }; |
2225 | 2396 | ||
@@ -2235,11 +2406,24 @@ static struct snd_kcontrol_new alc260_fujitsu_mixer[] = { | |||
2235 | HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT), | 2406 | HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT), |
2236 | HDA_CODEC_VOLUME("Internal Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT), | 2407 | HDA_CODEC_VOLUME("Internal Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT), |
2237 | HDA_BIND_MUTE("Internal Speaker Playback Switch", 0x09, 2, HDA_INPUT), | 2408 | HDA_BIND_MUTE("Internal Speaker Playback Switch", 0x09, 2, HDA_INPUT), |
2409 | { } /* end */ | ||
2410 | }; | ||
2411 | |||
2412 | /* capture mixer elements */ | ||
2413 | static struct snd_kcontrol_new alc260_capture_mixer[] = { | ||
2238 | HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT), | 2414 | HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT), |
2239 | HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT), | 2415 | HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT), |
2416 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x05, 0x0, HDA_INPUT), | ||
2417 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x05, 0x0, HDA_INPUT), | ||
2240 | { | 2418 | { |
2241 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2419 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
2242 | .name = "Capture Source", | 2420 | /* The multiple "Capture Source" controls confuse alsamixer |
2421 | * So call somewhat different.. | ||
2422 | * FIXME: the controls appear in the "playback" view! | ||
2423 | */ | ||
2424 | /* .name = "Capture Source", */ | ||
2425 | .name = "Input Source", | ||
2426 | .count = 2, | ||
2243 | .info = alc_mux_enum_info, | 2427 | .info = alc_mux_enum_info, |
2244 | .get = alc_mux_enum_get, | 2428 | .get = alc_mux_enum_get, |
2245 | .put = alc_mux_enum_put, | 2429 | .put = alc_mux_enum_put, |
@@ -2247,6 +2431,28 @@ static struct snd_kcontrol_new alc260_fujitsu_mixer[] = { | |||
2247 | { } /* end */ | 2431 | { } /* end */ |
2248 | }; | 2432 | }; |
2249 | 2433 | ||
2434 | static struct snd_kcontrol_new alc260_capture_alt_mixer[] = { | ||
2435 | HDA_CODEC_VOLUME("Capture Volume", 0x05, 0x0, HDA_INPUT), | ||
2436 | HDA_CODEC_MUTE("Capture Switch", 0x05, 0x0, HDA_INPUT), | ||
2437 | { | ||
2438 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2439 | /* The multiple "Capture Source" controls confuse alsamixer | ||
2440 | * So call somewhat different.. | ||
2441 | * FIXME: the controls appear in the "playback" view! | ||
2442 | */ | ||
2443 | /* .name = "Capture Source", */ | ||
2444 | .name = "Input Source", | ||
2445 | .count = 1, | ||
2446 | .info = alc_mux_enum_info, | ||
2447 | .get = alc_mux_enum_get, | ||
2448 | .put = alc_mux_enum_put, | ||
2449 | }, | ||
2450 | { } /* end */ | ||
2451 | }; | ||
2452 | |||
2453 | /* | ||
2454 | * initialization verbs | ||
2455 | */ | ||
2250 | static struct hda_verb alc260_init_verbs[] = { | 2456 | static struct hda_verb alc260_init_verbs[] = { |
2251 | /* Line In pin widget for input */ | 2457 | /* Line In pin widget for input */ |
2252 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | 2458 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, |
@@ -2308,6 +2514,100 @@ static struct hda_verb alc260_init_verbs[] = { | |||
2308 | { } | 2514 | { } |
2309 | }; | 2515 | }; |
2310 | 2516 | ||
2517 | static struct hda_verb alc260_hp_init_verbs[] = { | ||
2518 | /* Headphone and output */ | ||
2519 | {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, | ||
2520 | /* mono output */ | ||
2521 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
2522 | /* Mic1 (rear panel) pin widget for input and vref at 80% */ | ||
2523 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, | ||
2524 | /* Mic2 (front panel) pin widget for input and vref at 80% */ | ||
2525 | {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, | ||
2526 | /* Line In pin widget for input */ | ||
2527 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, | ||
2528 | /* Line-2 pin widget for output */ | ||
2529 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
2530 | /* CD pin widget for input */ | ||
2531 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, | ||
2532 | /* unmute amp left and right */ | ||
2533 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, | ||
2534 | /* set connection select to line in (default select for this ADC) */ | ||
2535 | {0x04, AC_VERB_SET_CONNECT_SEL, 0x02}, | ||
2536 | /* unmute Line-Out mixer amp left and right (volume = 0) */ | ||
2537 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
2538 | /* mute pin widget amp left and right (no gain on this amp) */ | ||
2539 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, | ||
2540 | /* unmute HP mixer amp left and right (volume = 0) */ | ||
2541 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
2542 | /* mute pin widget amp left and right (no gain on this amp) */ | ||
2543 | {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, | ||
2544 | /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */ | ||
2545 | /* unmute CD */ | ||
2546 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, | ||
2547 | /* unmute Line In */ | ||
2548 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, | ||
2549 | /* unmute Mic */ | ||
2550 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
2551 | /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ | ||
2552 | /* Unmute Front out path */ | ||
2553 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
2554 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
2555 | /* Unmute Headphone out path */ | ||
2556 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
2557 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
2558 | /* Unmute Mono out path */ | ||
2559 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
2560 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
2561 | { } | ||
2562 | }; | ||
2563 | |||
2564 | static struct hda_verb alc260_hp_3013_init_verbs[] = { | ||
2565 | /* Line out and output */ | ||
2566 | {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
2567 | /* mono output */ | ||
2568 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
2569 | /* Mic1 (rear panel) pin widget for input and vref at 80% */ | ||
2570 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, | ||
2571 | /* Mic2 (front panel) pin widget for input and vref at 80% */ | ||
2572 | {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, | ||
2573 | /* Line In pin widget for input */ | ||
2574 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, | ||
2575 | /* Headphone pin widget for output */ | ||
2576 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, | ||
2577 | /* CD pin widget for input */ | ||
2578 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, | ||
2579 | /* unmute amp left and right */ | ||
2580 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, | ||
2581 | /* set connection select to line in (default select for this ADC) */ | ||
2582 | {0x04, AC_VERB_SET_CONNECT_SEL, 0x02}, | ||
2583 | /* unmute Line-Out mixer amp left and right (volume = 0) */ | ||
2584 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
2585 | /* mute pin widget amp left and right (no gain on this amp) */ | ||
2586 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, | ||
2587 | /* unmute HP mixer amp left and right (volume = 0) */ | ||
2588 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
2589 | /* mute pin widget amp left and right (no gain on this amp) */ | ||
2590 | {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, | ||
2591 | /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */ | ||
2592 | /* unmute CD */ | ||
2593 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, | ||
2594 | /* unmute Line In */ | ||
2595 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, | ||
2596 | /* unmute Mic */ | ||
2597 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
2598 | /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ | ||
2599 | /* Unmute Front out path */ | ||
2600 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
2601 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
2602 | /* Unmute Headphone out path */ | ||
2603 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
2604 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
2605 | /* Unmute Mono out path */ | ||
2606 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
2607 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
2608 | { } | ||
2609 | }; | ||
2610 | |||
2311 | /* Initialisation sequence for ALC260 as configured in Fujitsu S702x | 2611 | /* Initialisation sequence for ALC260 as configured in Fujitsu S702x |
2312 | * laptops. | 2612 | * laptops. |
2313 | */ | 2613 | */ |
@@ -2374,18 +2674,337 @@ static struct hda_pcm_stream alc260_pcm_analog_capture = { | |||
2374 | .channels_max = 2, | 2674 | .channels_max = 2, |
2375 | }; | 2675 | }; |
2376 | 2676 | ||
2677 | /* | ||
2678 | * for BIOS auto-configuration | ||
2679 | */ | ||
2680 | |||
2681 | static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid, | ||
2682 | const char *pfx) | ||
2683 | { | ||
2684 | hda_nid_t nid_vol; | ||
2685 | unsigned long vol_val, sw_val; | ||
2686 | char name[32]; | ||
2687 | int err; | ||
2688 | |||
2689 | if (nid >= 0x0f && nid < 0x11) { | ||
2690 | nid_vol = nid - 0x7; | ||
2691 | vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT); | ||
2692 | sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); | ||
2693 | } else if (nid == 0x11) { | ||
2694 | nid_vol = nid - 0x7; | ||
2695 | vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT); | ||
2696 | sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT); | ||
2697 | } else if (nid >= 0x12 && nid <= 0x15) { | ||
2698 | nid_vol = 0x08; | ||
2699 | vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT); | ||
2700 | sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); | ||
2701 | } else | ||
2702 | return 0; /* N/A */ | ||
2703 | |||
2704 | snprintf(name, sizeof(name), "%s Playback Volume", pfx); | ||
2705 | if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name, vol_val)) < 0) | ||
2706 | return err; | ||
2707 | snprintf(name, sizeof(name), "%s Playback Switch", pfx); | ||
2708 | if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, sw_val)) < 0) | ||
2709 | return err; | ||
2710 | return 1; | ||
2711 | } | ||
2712 | |||
2713 | /* add playback controls from the parsed DAC table */ | ||
2714 | static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec, | ||
2715 | const struct auto_pin_cfg *cfg) | ||
2716 | { | ||
2717 | hda_nid_t nid; | ||
2718 | int err; | ||
2719 | |||
2720 | spec->multiout.num_dacs = 1; | ||
2721 | spec->multiout.dac_nids = spec->private_dac_nids; | ||
2722 | spec->multiout.dac_nids[0] = 0x02; | ||
2723 | |||
2724 | nid = cfg->line_out_pins[0]; | ||
2725 | if (nid) { | ||
2726 | err = alc260_add_playback_controls(spec, nid, "Front"); | ||
2727 | if (err < 0) | ||
2728 | return err; | ||
2729 | } | ||
2730 | |||
2731 | nid = cfg->speaker_pin; | ||
2732 | if (nid) { | ||
2733 | err = alc260_add_playback_controls(spec, nid, "Speaker"); | ||
2734 | if (err < 0) | ||
2735 | return err; | ||
2736 | } | ||
2737 | |||
2738 | nid = cfg->hp_pin; | ||
2739 | if (nid) { | ||
2740 | err = alc260_add_playback_controls(spec, nid, "Headphone"); | ||
2741 | if (err < 0) | ||
2742 | return err; | ||
2743 | } | ||
2744 | return 0; | ||
2745 | } | ||
2746 | |||
2747 | /* create playback/capture controls for input pins */ | ||
2748 | static int alc260_auto_create_analog_input_ctls(struct alc_spec *spec, | ||
2749 | const struct auto_pin_cfg *cfg) | ||
2750 | { | ||
2751 | static char *labels[AUTO_PIN_LAST] = { | ||
2752 | "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux" | ||
2753 | }; | ||
2754 | struct hda_input_mux *imux = &spec->private_imux; | ||
2755 | int i, err, idx; | ||
2756 | |||
2757 | for (i = 0; i < AUTO_PIN_LAST; i++) { | ||
2758 | if (cfg->input_pins[i] >= 0x12) { | ||
2759 | idx = cfg->input_pins[i] - 0x12; | ||
2760 | err = new_analog_input(spec, cfg->input_pins[i], labels[i], idx, 0x07); | ||
2761 | if (err < 0) | ||
2762 | return err; | ||
2763 | imux->items[imux->num_items].label = labels[i]; | ||
2764 | imux->items[imux->num_items].index = idx; | ||
2765 | imux->num_items++; | ||
2766 | } | ||
2767 | if ((cfg->input_pins[i] >= 0x0f) && (cfg->input_pins[i] <= 0x10)){ | ||
2768 | idx = cfg->input_pins[i] - 0x09; | ||
2769 | err = new_analog_input(spec, cfg->input_pins[i], labels[i], idx, 0x07); | ||
2770 | if (err < 0) | ||
2771 | return err; | ||
2772 | imux->items[imux->num_items].label = labels[i]; | ||
2773 | imux->items[imux->num_items].index = idx; | ||
2774 | imux->num_items++; | ||
2775 | } | ||
2776 | } | ||
2777 | return 0; | ||
2778 | } | ||
2779 | |||
2780 | static void alc260_auto_set_output_and_unmute(struct hda_codec *codec, | ||
2781 | hda_nid_t nid, int pin_type, | ||
2782 | int sel_idx) | ||
2783 | { | ||
2784 | /* set as output */ | ||
2785 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); | ||
2786 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); | ||
2787 | /* need the manual connection? */ | ||
2788 | if (nid >= 0x12) { | ||
2789 | int idx = nid - 0x12; | ||
2790 | snd_hda_codec_write(codec, idx + 0x0b, 0, | ||
2791 | AC_VERB_SET_CONNECT_SEL, sel_idx); | ||
2792 | |||
2793 | } | ||
2794 | } | ||
2795 | |||
2796 | static void alc260_auto_init_multi_out(struct hda_codec *codec) | ||
2797 | { | ||
2798 | struct alc_spec *spec = codec->spec; | ||
2799 | hda_nid_t nid; | ||
2800 | |||
2801 | nid = spec->autocfg.line_out_pins[0]; | ||
2802 | if (nid) | ||
2803 | alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0); | ||
2804 | |||
2805 | nid = spec->autocfg.speaker_pin; | ||
2806 | if (nid) | ||
2807 | alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0); | ||
2808 | |||
2809 | nid = spec->autocfg.hp_pin; | ||
2810 | if (nid) | ||
2811 | alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0); | ||
2812 | } | ||
2813 | |||
2814 | #define ALC260_PIN_CD_NID 0x16 | ||
2815 | static void alc260_auto_init_analog_input(struct hda_codec *codec) | ||
2816 | { | ||
2817 | struct alc_spec *spec = codec->spec; | ||
2818 | int i; | ||
2819 | |||
2820 | for (i = 0; i < AUTO_PIN_LAST; i++) { | ||
2821 | hda_nid_t nid = spec->autocfg.input_pins[i]; | ||
2822 | if (nid >= 0x12) { | ||
2823 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
2824 | i <= AUTO_PIN_FRONT_MIC ? PIN_VREF80 : PIN_IN); | ||
2825 | if (nid != ALC260_PIN_CD_NID) | ||
2826 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, | ||
2827 | AMP_OUT_MUTE); | ||
2828 | } | ||
2829 | } | ||
2830 | } | ||
2831 | |||
2832 | /* | ||
2833 | * generic initialization of ADC, input mixers and output mixers | ||
2834 | */ | ||
2835 | static struct hda_verb alc260_volume_init_verbs[] = { | ||
2836 | /* | ||
2837 | * Unmute ADC0-1 and set the default input to mic-in | ||
2838 | */ | ||
2839 | {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
2840 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
2841 | {0x05, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
2842 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
2843 | |||
2844 | /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback | ||
2845 | * mixer widget | ||
2846 | * Note: PASD motherboards uses the Line In 2 as the input for front panel | ||
2847 | * mic (mic 2) | ||
2848 | */ | ||
2849 | /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ | ||
2850 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
2851 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
2852 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | ||
2853 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, | ||
2854 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, | ||
2855 | |||
2856 | /* | ||
2857 | * Set up output mixers (0x08 - 0x0a) | ||
2858 | */ | ||
2859 | /* set vol=0 to output mixers */ | ||
2860 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
2861 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
2862 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
2863 | /* set up input amps for analog loopback */ | ||
2864 | /* Amp Indices: DAC = 0, mixer = 1 */ | ||
2865 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
2866 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
2867 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
2868 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
2869 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
2870 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
2871 | |||
2872 | { } | ||
2873 | }; | ||
2874 | |||
2875 | static int alc260_parse_auto_config(struct hda_codec *codec) | ||
2876 | { | ||
2877 | struct alc_spec *spec = codec->spec; | ||
2878 | unsigned int wcap; | ||
2879 | int err; | ||
2880 | static hda_nid_t alc260_ignore[] = { 0x17, 0 }; | ||
2881 | |||
2882 | if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, | ||
2883 | alc260_ignore)) < 0) | ||
2884 | return err; | ||
2885 | if (! spec->autocfg.line_outs && ! spec->autocfg.speaker_pin && | ||
2886 | ! spec->autocfg.hp_pin) | ||
2887 | return 0; /* can't find valid BIOS pin config */ | ||
2888 | if ((err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 || | ||
2889 | (err = alc260_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) | ||
2890 | return err; | ||
2891 | |||
2892 | spec->multiout.max_channels = 2; | ||
2893 | |||
2894 | if (spec->autocfg.dig_out_pin) | ||
2895 | spec->multiout.dig_out_nid = ALC260_DIGOUT_NID; | ||
2896 | if (spec->kctl_alloc) | ||
2897 | spec->mixers[spec->num_mixers++] = spec->kctl_alloc; | ||
2898 | |||
2899 | spec->init_verbs[spec->num_init_verbs++] = alc260_volume_init_verbs; | ||
2900 | |||
2901 | spec->input_mux = &spec->private_imux; | ||
2902 | |||
2903 | /* check whether NID 0x04 is valid */ | ||
2904 | wcap = snd_hda_param_read(codec, alc260_adc_nids[0], AC_PAR_AUDIO_WIDGET_CAP); | ||
2905 | wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */ | ||
2906 | if (wcap != AC_WID_AUD_IN) { | ||
2907 | spec->adc_nids = alc260_adc_nids_alt; | ||
2908 | spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt); | ||
2909 | spec->mixers[spec->num_mixers] = alc260_capture_alt_mixer; | ||
2910 | spec->num_mixers++; | ||
2911 | } else { | ||
2912 | spec->adc_nids = alc260_adc_nids; | ||
2913 | spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids); | ||
2914 | spec->mixers[spec->num_mixers] = alc260_capture_mixer; | ||
2915 | spec->num_mixers++; | ||
2916 | } | ||
2917 | |||
2918 | return 1; | ||
2919 | } | ||
2920 | |||
2921 | /* init callback for auto-configuration model -- overriding the default init */ | ||
2922 | static int alc260_auto_init(struct hda_codec *codec) | ||
2923 | { | ||
2924 | alc_init(codec); | ||
2925 | alc260_auto_init_multi_out(codec); | ||
2926 | alc260_auto_init_analog_input(codec); | ||
2927 | return 0; | ||
2928 | } | ||
2929 | |||
2930 | /* | ||
2931 | * ALC260 configurations | ||
2932 | */ | ||
2377 | static struct hda_board_config alc260_cfg_tbl[] = { | 2933 | static struct hda_board_config alc260_cfg_tbl[] = { |
2934 | { .modelname = "basic", .config = ALC260_BASIC }, | ||
2378 | { .modelname = "hp", .config = ALC260_HP }, | 2935 | { .modelname = "hp", .config = ALC260_HP }, |
2379 | { .pci_subvendor = 0x103c, .config = ALC260_HP }, | 2936 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3010, .config = ALC260_HP }, |
2380 | { .modelname = "fujitsu", .config = ALC260_FUJITSU_S702x }, | 2937 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3011, .config = ALC260_HP }, |
2381 | { .pci_subvendor = 0x10cf, .pci_subdevice = 0x1326, .config = ALC260_FUJITSU_S702x }, | 2938 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3012, .config = ALC260_HP }, |
2939 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3013, .config = ALC260_HP_3013 }, | ||
2940 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3014, .config = ALC260_HP }, | ||
2941 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3015, .config = ALC260_HP }, | ||
2942 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3016, .config = ALC260_HP }, | ||
2943 | { .modelname = "fujitsu", .config = ALC260_FUJITSU_S702X }, | ||
2944 | { .pci_subvendor = 0x10cf, .pci_subdevice = 0x1326, .config = ALC260_FUJITSU_S702X }, | ||
2945 | { .modelname = "auto", .config = ALC260_AUTO }, | ||
2382 | {} | 2946 | {} |
2383 | }; | 2947 | }; |
2384 | 2948 | ||
2949 | static struct alc_config_preset alc260_presets[] = { | ||
2950 | [ALC260_BASIC] = { | ||
2951 | .mixers = { alc260_base_output_mixer, | ||
2952 | alc260_input_mixer, | ||
2953 | alc260_pc_beep_mixer, | ||
2954 | alc260_capture_mixer }, | ||
2955 | .init_verbs = { alc260_init_verbs }, | ||
2956 | .num_dacs = ARRAY_SIZE(alc260_dac_nids), | ||
2957 | .dac_nids = alc260_dac_nids, | ||
2958 | .num_adc_nids = ARRAY_SIZE(alc260_adc_nids), | ||
2959 | .adc_nids = alc260_adc_nids, | ||
2960 | .num_channel_mode = ARRAY_SIZE(alc260_modes), | ||
2961 | .channel_mode = alc260_modes, | ||
2962 | .input_mux = &alc260_capture_source, | ||
2963 | }, | ||
2964 | [ALC260_HP] = { | ||
2965 | .mixers = { alc260_base_output_mixer, | ||
2966 | alc260_input_mixer, | ||
2967 | alc260_capture_alt_mixer }, | ||
2968 | .init_verbs = { alc260_hp_init_verbs }, | ||
2969 | .num_dacs = ARRAY_SIZE(alc260_dac_nids), | ||
2970 | .dac_nids = alc260_dac_nids, | ||
2971 | .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids), | ||
2972 | .adc_nids = alc260_hp_adc_nids, | ||
2973 | .num_channel_mode = ARRAY_SIZE(alc260_modes), | ||
2974 | .channel_mode = alc260_modes, | ||
2975 | .input_mux = &alc260_capture_source, | ||
2976 | }, | ||
2977 | [ALC260_HP_3013] = { | ||
2978 | .mixers = { alc260_hp_3013_mixer, | ||
2979 | alc260_input_mixer, | ||
2980 | alc260_capture_alt_mixer }, | ||
2981 | .init_verbs = { alc260_hp_3013_init_verbs }, | ||
2982 | .num_dacs = ARRAY_SIZE(alc260_dac_nids), | ||
2983 | .dac_nids = alc260_dac_nids, | ||
2984 | .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids), | ||
2985 | .adc_nids = alc260_hp_adc_nids, | ||
2986 | .num_channel_mode = ARRAY_SIZE(alc260_modes), | ||
2987 | .channel_mode = alc260_modes, | ||
2988 | .input_mux = &alc260_capture_source, | ||
2989 | }, | ||
2990 | [ALC260_FUJITSU_S702X] = { | ||
2991 | .mixers = { alc260_fujitsu_mixer, | ||
2992 | alc260_capture_mixer }, | ||
2993 | .init_verbs = { alc260_fujitsu_init_verbs }, | ||
2994 | .num_dacs = ARRAY_SIZE(alc260_dac_nids), | ||
2995 | .dac_nids = alc260_dac_nids, | ||
2996 | .num_adc_nids = ARRAY_SIZE(alc260_adc_nids), | ||
2997 | .adc_nids = alc260_adc_nids, | ||
2998 | .num_channel_mode = ARRAY_SIZE(alc260_modes), | ||
2999 | .channel_mode = alc260_modes, | ||
3000 | .input_mux = &alc260_fujitsu_capture_source, | ||
3001 | }, | ||
3002 | }; | ||
3003 | |||
2385 | static int patch_alc260(struct hda_codec *codec) | 3004 | static int patch_alc260(struct hda_codec *codec) |
2386 | { | 3005 | { |
2387 | struct alc_spec *spec; | 3006 | struct alc_spec *spec; |
2388 | int board_config; | 3007 | int err, board_config; |
2389 | 3008 | ||
2390 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 3009 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
2391 | if (spec == NULL) | 3010 | if (spec == NULL) |
@@ -2396,60 +3015,31 @@ static int patch_alc260(struct hda_codec *codec) | |||
2396 | board_config = snd_hda_check_board_config(codec, alc260_cfg_tbl); | 3015 | board_config = snd_hda_check_board_config(codec, alc260_cfg_tbl); |
2397 | if (board_config < 0 || board_config >= ALC260_MODEL_LAST) { | 3016 | if (board_config < 0 || board_config >= ALC260_MODEL_LAST) { |
2398 | snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260\n"); | 3017 | snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260\n"); |
2399 | board_config = ALC260_BASIC; | 3018 | board_config = ALC260_AUTO; |
2400 | } | 3019 | } |
2401 | 3020 | ||
2402 | switch (board_config) { | 3021 | if (board_config == ALC260_AUTO) { |
2403 | case ALC260_HP: | 3022 | /* automatic parse from the BIOS config */ |
2404 | spec->mixers[spec->num_mixers] = alc260_hp_mixer; | 3023 | err = alc260_parse_auto_config(codec); |
2405 | spec->num_mixers++; | 3024 | if (err < 0) { |
2406 | break; | 3025 | alc_free(codec); |
2407 | case ALC260_FUJITSU_S702x: | 3026 | return err; |
2408 | spec->mixers[spec->num_mixers] = alc260_fujitsu_mixer; | 3027 | } else if (! err) { |
2409 | spec->num_mixers++; | 3028 | printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using base mode...\n"); |
2410 | break; | 3029 | board_config = ALC260_BASIC; |
2411 | default: | 3030 | } |
2412 | spec->mixers[spec->num_mixers] = alc260_base_mixer; | ||
2413 | spec->num_mixers++; | ||
2414 | break; | ||
2415 | } | ||
2416 | |||
2417 | if (board_config != ALC260_FUJITSU_S702x) { | ||
2418 | spec->init_verbs[0] = alc260_init_verbs; | ||
2419 | spec->num_init_verbs = 1; | ||
2420 | } else { | ||
2421 | spec->init_verbs[0] = alc260_fujitsu_init_verbs; | ||
2422 | spec->num_init_verbs = 1; | ||
2423 | } | 3031 | } |
2424 | 3032 | ||
2425 | spec->channel_mode = alc260_modes; | 3033 | if (board_config != ALC260_AUTO) |
2426 | spec->num_channel_mode = ARRAY_SIZE(alc260_modes); | 3034 | setup_preset(spec, &alc260_presets[board_config]); |
2427 | 3035 | ||
2428 | spec->stream_name_analog = "ALC260 Analog"; | 3036 | spec->stream_name_analog = "ALC260 Analog"; |
2429 | spec->stream_analog_playback = &alc260_pcm_analog_playback; | 3037 | spec->stream_analog_playback = &alc260_pcm_analog_playback; |
2430 | spec->stream_analog_capture = &alc260_pcm_analog_capture; | 3038 | spec->stream_analog_capture = &alc260_pcm_analog_capture; |
2431 | 3039 | ||
2432 | spec->multiout.max_channels = spec->channel_mode[0].channels; | ||
2433 | spec->multiout.num_dacs = ARRAY_SIZE(alc260_dac_nids); | ||
2434 | spec->multiout.dac_nids = alc260_dac_nids; | ||
2435 | |||
2436 | if (board_config != ALC260_FUJITSU_S702x) { | ||
2437 | spec->input_mux = &alc260_capture_source; | ||
2438 | } else { | ||
2439 | spec->input_mux = &alc260_fujitsu_capture_source; | ||
2440 | } | ||
2441 | switch (board_config) { | ||
2442 | case ALC260_HP: | ||
2443 | spec->num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids); | ||
2444 | spec->adc_nids = alc260_hp_adc_nids; | ||
2445 | break; | ||
2446 | default: | ||
2447 | spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids); | ||
2448 | spec->adc_nids = alc260_adc_nids; | ||
2449 | break; | ||
2450 | } | ||
2451 | |||
2452 | codec->patch_ops = alc_patch_ops; | 3040 | codec->patch_ops = alc_patch_ops; |
3041 | if (board_config == ALC260_AUTO) | ||
3042 | codec->patch_ops.init = alc260_auto_init; | ||
2453 | 3043 | ||
2454 | return 0; | 3044 | return 0; |
2455 | } | 3045 | } |
@@ -2466,6 +3056,8 @@ static int patch_alc260(struct hda_codec *codec) | |||
2466 | * In addition, an independent DAC for the multi-playback (not used in this | 3056 | * In addition, an independent DAC for the multi-playback (not used in this |
2467 | * driver yet). | 3057 | * driver yet). |
2468 | */ | 3058 | */ |
3059 | #define ALC882_DIGOUT_NID 0x06 | ||
3060 | #define ALC882_DIGIN_NID 0x0a | ||
2469 | 3061 | ||
2470 | static struct hda_channel_mode alc882_ch_modes[1] = { | 3062 | static struct hda_channel_mode alc882_ch_modes[1] = { |
2471 | { 8, NULL } | 3063 | { 8, NULL } |
@@ -2476,10 +3068,9 @@ static hda_nid_t alc882_dac_nids[4] = { | |||
2476 | 0x02, 0x03, 0x04, 0x05 | 3068 | 0x02, 0x03, 0x04, 0x05 |
2477 | }; | 3069 | }; |
2478 | 3070 | ||
2479 | static hda_nid_t alc882_adc_nids[3] = { | 3071 | /* identical with ALC880 */ |
2480 | /* ADC0-2 */ | 3072 | #define alc882_adc_nids alc880_adc_nids |
2481 | 0x07, 0x08, 0x09, | 3073 | #define alc882_adc_nids_alt alc880_adc_nids_alt |
2482 | }; | ||
2483 | 3074 | ||
2484 | /* input MUX */ | 3075 | /* input MUX */ |
2485 | /* FIXME: should be a matrix-type input source selection */ | 3076 | /* FIXME: should be a matrix-type input source selection */ |
@@ -2522,6 +3113,33 @@ static int alc882_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ele | |||
2522 | return 1; | 3113 | return 1; |
2523 | } | 3114 | } |
2524 | 3115 | ||
3116 | /* | ||
3117 | * 6ch mode | ||
3118 | */ | ||
3119 | static struct hda_verb alc882_sixstack_ch6_init[] = { | ||
3120 | { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, | ||
3121 | { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
3122 | { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
3123 | { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
3124 | { } /* end */ | ||
3125 | }; | ||
3126 | |||
3127 | /* | ||
3128 | * 8ch mode | ||
3129 | */ | ||
3130 | static struct hda_verb alc882_sixstack_ch8_init[] = { | ||
3131 | { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
3132 | { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
3133 | { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
3134 | { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
3135 | { } /* end */ | ||
3136 | }; | ||
3137 | |||
3138 | static struct hda_channel_mode alc882_sixstack_modes[2] = { | ||
3139 | { 6, alc882_sixstack_ch6_init }, | ||
3140 | { 8, alc882_sixstack_ch8_init }, | ||
3141 | }; | ||
3142 | |||
2525 | /* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 | 3143 | /* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 |
2526 | * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b | 3144 | * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b |
2527 | */ | 3145 | */ |
@@ -2565,6 +3183,17 @@ static struct snd_kcontrol_new alc882_base_mixer[] = { | |||
2565 | { } /* end */ | 3183 | { } /* end */ |
2566 | }; | 3184 | }; |
2567 | 3185 | ||
3186 | static struct snd_kcontrol_new alc882_chmode_mixer[] = { | ||
3187 | { | ||
3188 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3189 | .name = "Channel Mode", | ||
3190 | .info = alc_ch_mode_info, | ||
3191 | .get = alc_ch_mode_get, | ||
3192 | .put = alc_ch_mode_put, | ||
3193 | }, | ||
3194 | { } /* end */ | ||
3195 | }; | ||
3196 | |||
2568 | static struct hda_verb alc882_init_verbs[] = { | 3197 | static struct hda_verb alc882_init_verbs[] = { |
2569 | /* Front mixer: unmute input/output amp left and right (volume = 0) */ | 3198 | /* Front mixer: unmute input/output amp left and right (volume = 0) */ |
2570 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | 3199 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, |
@@ -2645,9 +3274,263 @@ static struct hda_verb alc882_init_verbs[] = { | |||
2645 | { } | 3274 | { } |
2646 | }; | 3275 | }; |
2647 | 3276 | ||
3277 | /* | ||
3278 | * generic initialization of ADC, input mixers and output mixers | ||
3279 | */ | ||
3280 | static struct hda_verb alc882_auto_init_verbs[] = { | ||
3281 | /* | ||
3282 | * Unmute ADC0-2 and set the default input to mic-in | ||
3283 | */ | ||
3284 | {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
3285 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3286 | {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
3287 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3288 | {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
3289 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3290 | |||
3291 | /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback | ||
3292 | * mixer widget | ||
3293 | * Note: PASD motherboards uses the Line In 2 as the input for front panel | ||
3294 | * mic (mic 2) | ||
3295 | */ | ||
3296 | /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ | ||
3297 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3298 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
3299 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | ||
3300 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, | ||
3301 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, | ||
3302 | |||
3303 | /* | ||
3304 | * Set up output mixers (0x0c - 0x0f) | ||
3305 | */ | ||
3306 | /* set vol=0 to output mixers */ | ||
3307 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
3308 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
3309 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
3310 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
3311 | /* set up input amps for analog loopback */ | ||
3312 | /* Amp Indices: DAC = 0, mixer = 1 */ | ||
3313 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3314 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
3315 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3316 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
3317 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3318 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
3319 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3320 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
3321 | {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3322 | {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
3323 | |||
3324 | /* FIXME: use matrix-type input source selection */ | ||
3325 | /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ | ||
3326 | /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ | ||
3327 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
3328 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, | ||
3329 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, | ||
3330 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, | ||
3331 | /* Input mixer2 */ | ||
3332 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
3333 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, | ||
3334 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, | ||
3335 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, | ||
3336 | /* Input mixer3 */ | ||
3337 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
3338 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, | ||
3339 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, | ||
3340 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, | ||
3341 | |||
3342 | { } | ||
3343 | }; | ||
3344 | |||
3345 | /* capture mixer elements */ | ||
3346 | static struct snd_kcontrol_new alc882_capture_alt_mixer[] = { | ||
3347 | HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), | ||
3348 | HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), | ||
3349 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), | ||
3350 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), | ||
3351 | { | ||
3352 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3353 | /* The multiple "Capture Source" controls confuse alsamixer | ||
3354 | * So call somewhat different.. | ||
3355 | * FIXME: the controls appear in the "playback" view! | ||
3356 | */ | ||
3357 | /* .name = "Capture Source", */ | ||
3358 | .name = "Input Source", | ||
3359 | .count = 2, | ||
3360 | .info = alc882_mux_enum_info, | ||
3361 | .get = alc882_mux_enum_get, | ||
3362 | .put = alc882_mux_enum_put, | ||
3363 | }, | ||
3364 | { } /* end */ | ||
3365 | }; | ||
3366 | |||
3367 | static struct snd_kcontrol_new alc882_capture_mixer[] = { | ||
3368 | HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), | ||
3369 | HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), | ||
3370 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), | ||
3371 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), | ||
3372 | HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT), | ||
3373 | HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT), | ||
3374 | { | ||
3375 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3376 | /* The multiple "Capture Source" controls confuse alsamixer | ||
3377 | * So call somewhat different.. | ||
3378 | * FIXME: the controls appear in the "playback" view! | ||
3379 | */ | ||
3380 | /* .name = "Capture Source", */ | ||
3381 | .name = "Input Source", | ||
3382 | .count = 3, | ||
3383 | .info = alc882_mux_enum_info, | ||
3384 | .get = alc882_mux_enum_get, | ||
3385 | .put = alc882_mux_enum_put, | ||
3386 | }, | ||
3387 | { } /* end */ | ||
3388 | }; | ||
3389 | |||
3390 | /* pcm configuration: identiacal with ALC880 */ | ||
3391 | #define alc882_pcm_analog_playback alc880_pcm_analog_playback | ||
3392 | #define alc882_pcm_analog_capture alc880_pcm_analog_capture | ||
3393 | #define alc882_pcm_digital_playback alc880_pcm_digital_playback | ||
3394 | #define alc882_pcm_digital_capture alc880_pcm_digital_capture | ||
3395 | |||
3396 | /* | ||
3397 | * configuration and preset | ||
3398 | */ | ||
3399 | static struct hda_board_config alc882_cfg_tbl[] = { | ||
3400 | { .modelname = "3stack-dig", .config = ALC861_3ST_DIG }, | ||
3401 | { .modelname = "6stack-dig", .config = ALC861_6ST_DIG }, | ||
3402 | { .pci_subvendor = 0x1462, .pci_subdevice = 0x6668, .config = ALC882_6ST_DIG }, /* MSI */ | ||
3403 | { .pci_subvendor = 0x105b, .pci_subdevice = 0x6668, .config = ALC882_6ST_DIG }, /* Foxconn */ | ||
3404 | { .pci_subvendor = 0x1019, .pci_subdevice = 0x6668, .config = ALC882_6ST_DIG }, /* ECS */ | ||
3405 | { .modelname = "auto", .config = ALC861_AUTO }, | ||
3406 | {} | ||
3407 | }; | ||
3408 | |||
3409 | static struct alc_config_preset alc882_presets[] = { | ||
3410 | [ALC882_3ST_DIG] = { | ||
3411 | .mixers = { alc882_base_mixer }, | ||
3412 | .init_verbs = { alc882_init_verbs }, | ||
3413 | .num_dacs = ARRAY_SIZE(alc882_dac_nids), | ||
3414 | .dac_nids = alc882_dac_nids, | ||
3415 | .dig_out_nid = ALC882_DIGOUT_NID, | ||
3416 | .num_adc_nids = ARRAY_SIZE(alc882_adc_nids), | ||
3417 | .adc_nids = alc882_adc_nids, | ||
3418 | .dig_in_nid = ALC882_DIGIN_NID, | ||
3419 | .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), | ||
3420 | .channel_mode = alc882_ch_modes, | ||
3421 | .input_mux = &alc882_capture_source, | ||
3422 | }, | ||
3423 | [ALC882_6ST_DIG] = { | ||
3424 | .mixers = { alc882_base_mixer, alc882_chmode_mixer }, | ||
3425 | .init_verbs = { alc882_init_verbs }, | ||
3426 | .num_dacs = ARRAY_SIZE(alc882_dac_nids), | ||
3427 | .dac_nids = alc882_dac_nids, | ||
3428 | .dig_out_nid = ALC882_DIGOUT_NID, | ||
3429 | .num_adc_nids = ARRAY_SIZE(alc882_adc_nids), | ||
3430 | .adc_nids = alc882_adc_nids, | ||
3431 | .dig_in_nid = ALC882_DIGIN_NID, | ||
3432 | .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes), | ||
3433 | .channel_mode = alc882_sixstack_modes, | ||
3434 | .input_mux = &alc882_capture_source, | ||
3435 | }, | ||
3436 | }; | ||
3437 | |||
3438 | |||
3439 | /* | ||
3440 | * BIOS auto configuration | ||
3441 | */ | ||
3442 | static void alc882_auto_set_output_and_unmute(struct hda_codec *codec, | ||
3443 | hda_nid_t nid, int pin_type, | ||
3444 | int dac_idx) | ||
3445 | { | ||
3446 | /* set as output */ | ||
3447 | struct alc_spec *spec = codec->spec; | ||
3448 | int idx; | ||
3449 | |||
3450 | if (spec->multiout.dac_nids[dac_idx] == 0x25) | ||
3451 | idx = 4; | ||
3452 | else | ||
3453 | idx = spec->multiout.dac_nids[dac_idx] - 2; | ||
3454 | |||
3455 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); | ||
3456 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); | ||
3457 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx); | ||
3458 | |||
3459 | } | ||
3460 | |||
3461 | static void alc882_auto_init_multi_out(struct hda_codec *codec) | ||
3462 | { | ||
3463 | struct alc_spec *spec = codec->spec; | ||
3464 | int i; | ||
3465 | |||
3466 | for (i = 0; i <= HDA_SIDE; i++) { | ||
3467 | hda_nid_t nid = spec->autocfg.line_out_pins[i]; | ||
3468 | if (nid) | ||
3469 | alc882_auto_set_output_and_unmute(codec, nid, PIN_OUT, i); | ||
3470 | } | ||
3471 | } | ||
3472 | |||
3473 | static void alc882_auto_init_hp_out(struct hda_codec *codec) | ||
3474 | { | ||
3475 | struct alc_spec *spec = codec->spec; | ||
3476 | hda_nid_t pin; | ||
3477 | |||
3478 | pin = spec->autocfg.hp_pin; | ||
3479 | if (pin) /* connect to front */ | ||
3480 | alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); /* use dac 0 */ | ||
3481 | } | ||
3482 | |||
3483 | #define alc882_is_input_pin(nid) alc880_is_input_pin(nid) | ||
3484 | #define ALC882_PIN_CD_NID ALC880_PIN_CD_NID | ||
3485 | |||
3486 | static void alc882_auto_init_analog_input(struct hda_codec *codec) | ||
3487 | { | ||
3488 | struct alc_spec *spec = codec->spec; | ||
3489 | int i; | ||
3490 | |||
3491 | for (i = 0; i < AUTO_PIN_LAST; i++) { | ||
3492 | hda_nid_t nid = spec->autocfg.input_pins[i]; | ||
3493 | if (alc882_is_input_pin(nid)) { | ||
3494 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
3495 | i <= AUTO_PIN_FRONT_MIC ? PIN_VREF80 : PIN_IN); | ||
3496 | if (nid != ALC882_PIN_CD_NID) | ||
3497 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, | ||
3498 | AMP_OUT_MUTE); | ||
3499 | } | ||
3500 | } | ||
3501 | } | ||
3502 | |||
3503 | /* almost identical with ALC880 parser... */ | ||
3504 | static int alc882_parse_auto_config(struct hda_codec *codec) | ||
3505 | { | ||
3506 | struct alc_spec *spec = codec->spec; | ||
3507 | int err = alc880_parse_auto_config(codec); | ||
3508 | |||
3509 | if (err < 0) | ||
3510 | return err; | ||
3511 | /* hack - override the init verbs */ | ||
3512 | spec->init_verbs[0] = alc882_auto_init_verbs; | ||
3513 | return 0; | ||
3514 | } | ||
3515 | |||
3516 | /* init callback for auto-configuration model -- overriding the default init */ | ||
3517 | static int alc882_auto_init(struct hda_codec *codec) | ||
3518 | { | ||
3519 | alc_init(codec); | ||
3520 | alc882_auto_init_multi_out(codec); | ||
3521 | alc882_auto_init_hp_out(codec); | ||
3522 | alc882_auto_init_analog_input(codec); | ||
3523 | return 0; | ||
3524 | } | ||
3525 | |||
3526 | /* | ||
3527 | * ALC882 Headphone poll in 3.5.1a or 3.5.2 | ||
3528 | */ | ||
3529 | |||
2648 | static int patch_alc882(struct hda_codec *codec) | 3530 | static int patch_alc882(struct hda_codec *codec) |
2649 | { | 3531 | { |
2650 | struct alc_spec *spec; | 3532 | struct alc_spec *spec; |
3533 | int err, board_config; | ||
2651 | 3534 | ||
2652 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 3535 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
2653 | if (spec == NULL) | 3536 | if (spec == NULL) |
@@ -2655,35 +3538,1135 @@ static int patch_alc882(struct hda_codec *codec) | |||
2655 | 3538 | ||
2656 | codec->spec = spec; | 3539 | codec->spec = spec; |
2657 | 3540 | ||
2658 | spec->mixers[spec->num_mixers] = alc882_base_mixer; | 3541 | board_config = snd_hda_check_board_config(codec, alc882_cfg_tbl); |
2659 | spec->num_mixers++; | ||
2660 | 3542 | ||
2661 | spec->multiout.dig_out_nid = ALC880_DIGOUT_NID; | 3543 | if (board_config < 0 || board_config >= ALC882_MODEL_LAST) { |
2662 | spec->dig_in_nid = ALC880_DIGIN_NID; | 3544 | printk(KERN_INFO "hda_codec: Unknown model for ALC882, trying auto-probe from BIOS...\n"); |
2663 | spec->init_verbs[0] = alc882_init_verbs; | 3545 | board_config = ALC882_AUTO; |
2664 | spec->num_init_verbs = 1; | 3546 | } |
3547 | |||
3548 | if (board_config == ALC882_AUTO) { | ||
3549 | /* automatic parse from the BIOS config */ | ||
3550 | err = alc882_parse_auto_config(codec); | ||
3551 | if (err < 0) { | ||
3552 | alc_free(codec); | ||
3553 | return err; | ||
3554 | } else if (! err) { | ||
3555 | printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using base mode...\n"); | ||
3556 | board_config = ALC882_3ST_DIG; | ||
3557 | } | ||
3558 | } | ||
2665 | 3559 | ||
2666 | spec->channel_mode = alc882_ch_modes; | 3560 | if (board_config != ALC882_AUTO) |
2667 | spec->num_channel_mode = ARRAY_SIZE(alc882_ch_modes); | 3561 | setup_preset(spec, &alc882_presets[board_config]); |
2668 | 3562 | ||
2669 | spec->stream_name_analog = "ALC882 Analog"; | 3563 | spec->stream_name_analog = "ALC882 Analog"; |
2670 | spec->stream_analog_playback = &alc880_pcm_analog_playback; | 3564 | spec->stream_analog_playback = &alc882_pcm_analog_playback; |
2671 | spec->stream_analog_capture = &alc880_pcm_analog_capture; | 3565 | spec->stream_analog_capture = &alc882_pcm_analog_capture; |
2672 | 3566 | ||
2673 | spec->stream_name_digital = "ALC882 Digital"; | 3567 | spec->stream_name_digital = "ALC882 Digital"; |
2674 | spec->stream_digital_playback = &alc880_pcm_digital_playback; | 3568 | spec->stream_digital_playback = &alc882_pcm_digital_playback; |
2675 | spec->stream_digital_capture = &alc880_pcm_digital_capture; | 3569 | spec->stream_digital_capture = &alc882_pcm_digital_capture; |
2676 | 3570 | ||
2677 | spec->multiout.max_channels = spec->channel_mode[0].channels; | 3571 | if (! spec->adc_nids && spec->input_mux) { |
2678 | spec->multiout.num_dacs = ARRAY_SIZE(alc882_dac_nids); | 3572 | /* check whether NID 0x07 is valid */ |
2679 | spec->multiout.dac_nids = alc882_dac_nids; | 3573 | unsigned int wcap = snd_hda_param_read(codec, 0x07, |
3574 | AC_PAR_AUDIO_WIDGET_CAP); | ||
3575 | wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */ | ||
3576 | if (wcap != AC_WID_AUD_IN) { | ||
3577 | spec->adc_nids = alc882_adc_nids_alt; | ||
3578 | spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids_alt); | ||
3579 | spec->mixers[spec->num_mixers] = alc882_capture_alt_mixer; | ||
3580 | spec->num_mixers++; | ||
3581 | } else { | ||
3582 | spec->adc_nids = alc882_adc_nids; | ||
3583 | spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids); | ||
3584 | spec->mixers[spec->num_mixers] = alc882_capture_mixer; | ||
3585 | spec->num_mixers++; | ||
3586 | } | ||
3587 | } | ||
3588 | |||
3589 | codec->patch_ops = alc_patch_ops; | ||
3590 | if (board_config == ALC882_AUTO) | ||
3591 | codec->patch_ops.init = alc882_auto_init; | ||
2680 | 3592 | ||
2681 | spec->input_mux = &alc882_capture_source; | 3593 | return 0; |
2682 | spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids); | 3594 | } |
2683 | spec->adc_nids = alc882_adc_nids; | 3595 | |
3596 | /* | ||
3597 | * ALC262 support | ||
3598 | */ | ||
3599 | |||
3600 | #define ALC262_DIGOUT_NID ALC880_DIGOUT_NID | ||
3601 | #define ALC262_DIGIN_NID ALC880_DIGIN_NID | ||
3602 | |||
3603 | #define alc262_dac_nids alc260_dac_nids | ||
3604 | #define alc262_adc_nids alc882_adc_nids | ||
3605 | #define alc262_adc_nids_alt alc882_adc_nids_alt | ||
3606 | |||
3607 | #define alc262_modes alc260_modes | ||
3608 | |||
3609 | static struct snd_kcontrol_new alc262_base_mixer[] = { | ||
3610 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
3611 | HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), | ||
3612 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), | ||
3613 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), | ||
3614 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), | ||
3615 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), | ||
3616 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
3617 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
3618 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), | ||
3619 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), | ||
3620 | /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT), | ||
3621 | HDA_CODEC_MUTE("PC Beelp Playback Switch", 0x0b, 0x05, HDA_INPUT), */ | ||
3622 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT), | ||
3623 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
3624 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), | ||
3625 | HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), | ||
3626 | HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), | ||
3627 | HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), | ||
3628 | { | ||
3629 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3630 | .name = "Capture Source", | ||
3631 | .count = 1, | ||
3632 | .info = alc882_mux_enum_info, | ||
3633 | .get = alc882_mux_enum_get, | ||
3634 | .put = alc882_mux_enum_put, | ||
3635 | }, | ||
3636 | { } /* end */ | ||
3637 | }; | ||
3638 | |||
3639 | #define alc262_capture_mixer alc882_capture_mixer | ||
3640 | #define alc262_capture_alt_mixer alc882_capture_alt_mixer | ||
3641 | |||
3642 | /* | ||
3643 | * generic initialization of ADC, input mixers and output mixers | ||
3644 | */ | ||
3645 | static struct hda_verb alc262_init_verbs[] = { | ||
3646 | /* | ||
3647 | * Unmute ADC0-2 and set the default input to mic-in | ||
3648 | */ | ||
3649 | {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
3650 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3651 | {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
3652 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3653 | {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
3654 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3655 | |||
3656 | /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback | ||
3657 | * mixer widget | ||
3658 | * Note: PASD motherboards uses the Line In 2 as the input for front panel | ||
3659 | * mic (mic 2) | ||
3660 | */ | ||
3661 | /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ | ||
3662 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3663 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
3664 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | ||
3665 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, | ||
3666 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, | ||
3667 | |||
3668 | /* | ||
3669 | * Set up output mixers (0x0c - 0x0e) | ||
3670 | */ | ||
3671 | /* set vol=0 to output mixers */ | ||
3672 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
3673 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
3674 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
3675 | /* set up input amps for analog loopback */ | ||
3676 | /* Amp Indices: DAC = 0, mixer = 1 */ | ||
3677 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3678 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
3679 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3680 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
3681 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3682 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
3683 | |||
3684 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
3685 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, | ||
3686 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
3687 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, | ||
3688 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, | ||
3689 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, | ||
3690 | |||
3691 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, | ||
3692 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, | ||
3693 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, | ||
3694 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, | ||
3695 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, | ||
3696 | |||
3697 | {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
3698 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
3699 | |||
3700 | /* FIXME: use matrix-type input source selection */ | ||
3701 | /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ | ||
3702 | /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ | ||
3703 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
3704 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, | ||
3705 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, | ||
3706 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, | ||
3707 | /* Input mixer2 */ | ||
3708 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
3709 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, | ||
3710 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, | ||
3711 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, | ||
3712 | /* Input mixer3 */ | ||
3713 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
3714 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, | ||
3715 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, | ||
3716 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, | ||
3717 | |||
3718 | { } | ||
3719 | }; | ||
3720 | |||
3721 | /* add playback controls from the parsed DAC table */ | ||
3722 | static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg) | ||
3723 | { | ||
3724 | hda_nid_t nid; | ||
3725 | int err; | ||
3726 | |||
3727 | spec->multiout.num_dacs = 1; /* only use one dac */ | ||
3728 | spec->multiout.dac_nids = spec->private_dac_nids; | ||
3729 | spec->multiout.dac_nids[0] = 2; | ||
3730 | |||
3731 | nid = cfg->line_out_pins[0]; | ||
3732 | if (nid) { | ||
3733 | if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Front Playback Volume", | ||
3734 | HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT))) < 0) | ||
3735 | return err; | ||
3736 | if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Front Playback Switch", | ||
3737 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) | ||
3738 | return err; | ||
3739 | } | ||
3740 | |||
3741 | nid = cfg->speaker_pin; | ||
3742 | if (nid) { | ||
3743 | if (nid == 0x16) { | ||
3744 | if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Speaker Playback Volume", | ||
3745 | HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT))) < 0) | ||
3746 | return err; | ||
3747 | if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Speaker Playback Switch", | ||
3748 | HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0) | ||
3749 | return err; | ||
3750 | } else { | ||
3751 | if (! cfg->line_out_pins[0]) | ||
3752 | if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Speaker Playback Volume", | ||
3753 | HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT))) < 0) | ||
3754 | return err; | ||
3755 | if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Speaker Playback Switch", | ||
3756 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) | ||
3757 | return err; | ||
3758 | } | ||
3759 | } | ||
3760 | nid = cfg->hp_pin; | ||
3761 | if (nid) { | ||
3762 | /* spec->multiout.hp_nid = 2; */ | ||
3763 | if (nid == 0x16) { | ||
3764 | if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Headphone Playback Volume", | ||
3765 | HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT))) < 0) | ||
3766 | return err; | ||
3767 | if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Headphone Playback Switch", | ||
3768 | HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0) | ||
3769 | return err; | ||
3770 | } else { | ||
3771 | if (! cfg->line_out_pins[0]) | ||
3772 | if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Headphone Playback Volume", | ||
3773 | HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT))) < 0) | ||
3774 | return err; | ||
3775 | if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Headphone Playback Switch", | ||
3776 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) | ||
3777 | return err; | ||
3778 | } | ||
3779 | } | ||
3780 | return 0; | ||
3781 | } | ||
3782 | |||
3783 | /* identical with ALC880 */ | ||
3784 | #define alc262_auto_create_analog_input_ctls alc880_auto_create_analog_input_ctls | ||
3785 | |||
3786 | /* | ||
3787 | * generic initialization of ADC, input mixers and output mixers | ||
3788 | */ | ||
3789 | static struct hda_verb alc262_volume_init_verbs[] = { | ||
3790 | /* | ||
3791 | * Unmute ADC0-2 and set the default input to mic-in | ||
3792 | */ | ||
3793 | {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
3794 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3795 | {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
3796 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3797 | {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
3798 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3799 | |||
3800 | /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback | ||
3801 | * mixer widget | ||
3802 | * Note: PASD motherboards uses the Line In 2 as the input for front panel | ||
3803 | * mic (mic 2) | ||
3804 | */ | ||
3805 | /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ | ||
3806 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3807 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
3808 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | ||
3809 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, | ||
3810 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, | ||
3811 | |||
3812 | /* | ||
3813 | * Set up output mixers (0x0c - 0x0f) | ||
3814 | */ | ||
3815 | /* set vol=0 to output mixers */ | ||
3816 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
3817 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
3818 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
3819 | |||
3820 | /* set up input amps for analog loopback */ | ||
3821 | /* Amp Indices: DAC = 0, mixer = 1 */ | ||
3822 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3823 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
3824 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3825 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
3826 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
3827 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
3828 | |||
3829 | /* FIXME: use matrix-type input source selection */ | ||
3830 | /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ | ||
3831 | /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ | ||
3832 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
3833 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, | ||
3834 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, | ||
3835 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, | ||
3836 | /* Input mixer2 */ | ||
3837 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
3838 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, | ||
3839 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, | ||
3840 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, | ||
3841 | /* Input mixer3 */ | ||
3842 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
3843 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, | ||
3844 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, | ||
3845 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, | ||
3846 | |||
3847 | { } | ||
3848 | }; | ||
3849 | |||
3850 | /* pcm configuration: identiacal with ALC880 */ | ||
3851 | #define alc262_pcm_analog_playback alc880_pcm_analog_playback | ||
3852 | #define alc262_pcm_analog_capture alc880_pcm_analog_capture | ||
3853 | #define alc262_pcm_digital_playback alc880_pcm_digital_playback | ||
3854 | #define alc262_pcm_digital_capture alc880_pcm_digital_capture | ||
3855 | |||
3856 | /* | ||
3857 | * BIOS auto configuration | ||
3858 | */ | ||
3859 | static int alc262_parse_auto_config(struct hda_codec *codec) | ||
3860 | { | ||
3861 | struct alc_spec *spec = codec->spec; | ||
3862 | int err; | ||
3863 | static hda_nid_t alc262_ignore[] = { 0x1d, 0 }; | ||
3864 | |||
3865 | if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, | ||
3866 | alc262_ignore)) < 0) | ||
3867 | return err; | ||
3868 | if (! spec->autocfg.line_outs && ! spec->autocfg.speaker_pin && | ||
3869 | ! spec->autocfg.hp_pin) | ||
3870 | return 0; /* can't find valid BIOS pin config */ | ||
3871 | if ((err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 || | ||
3872 | (err = alc262_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) | ||
3873 | return err; | ||
3874 | |||
3875 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; | ||
3876 | |||
3877 | if (spec->autocfg.dig_out_pin) | ||
3878 | spec->multiout.dig_out_nid = ALC262_DIGOUT_NID; | ||
3879 | if (spec->autocfg.dig_in_pin) | ||
3880 | spec->dig_in_nid = ALC262_DIGIN_NID; | ||
3881 | |||
3882 | if (spec->kctl_alloc) | ||
3883 | spec->mixers[spec->num_mixers++] = spec->kctl_alloc; | ||
3884 | |||
3885 | spec->init_verbs[spec->num_init_verbs++] = alc262_volume_init_verbs; | ||
3886 | spec->input_mux = &spec->private_imux; | ||
3887 | |||
3888 | return 1; | ||
3889 | } | ||
3890 | |||
3891 | #define alc262_auto_init_multi_out alc882_auto_init_multi_out | ||
3892 | #define alc262_auto_init_hp_out alc882_auto_init_hp_out | ||
3893 | #define alc262_auto_init_analog_input alc882_auto_init_analog_input | ||
3894 | |||
3895 | |||
3896 | /* init callback for auto-configuration model -- overriding the default init */ | ||
3897 | static int alc262_auto_init(struct hda_codec *codec) | ||
3898 | { | ||
3899 | alc_init(codec); | ||
3900 | alc262_auto_init_multi_out(codec); | ||
3901 | alc262_auto_init_hp_out(codec); | ||
3902 | alc262_auto_init_analog_input(codec); | ||
3903 | return 0; | ||
3904 | } | ||
3905 | |||
3906 | /* | ||
3907 | * configuration and preset | ||
3908 | */ | ||
3909 | static struct hda_board_config alc262_cfg_tbl[] = { | ||
3910 | { .modelname = "basic", .config = ALC262_BASIC }, | ||
3911 | { .modelname = "auto", .config = ALC262_AUTO }, | ||
3912 | {} | ||
3913 | }; | ||
3914 | |||
3915 | static struct alc_config_preset alc262_presets[] = { | ||
3916 | [ALC262_BASIC] = { | ||
3917 | .mixers = { alc262_base_mixer }, | ||
3918 | .init_verbs = { alc262_init_verbs }, | ||
3919 | .num_dacs = ARRAY_SIZE(alc262_dac_nids), | ||
3920 | .dac_nids = alc262_dac_nids, | ||
3921 | .hp_nid = 0x03, | ||
3922 | .num_channel_mode = ARRAY_SIZE(alc262_modes), | ||
3923 | .channel_mode = alc262_modes, | ||
3924 | }, | ||
3925 | }; | ||
3926 | |||
3927 | static int patch_alc262(struct hda_codec *codec) | ||
3928 | { | ||
3929 | struct alc_spec *spec; | ||
3930 | int board_config; | ||
3931 | int err; | ||
3932 | |||
3933 | spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); | ||
3934 | if (spec == NULL) | ||
3935 | return -ENOMEM; | ||
3936 | |||
3937 | codec->spec = spec; | ||
3938 | #if 0 | ||
3939 | /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is under-run */ | ||
3940 | { | ||
3941 | int tmp; | ||
3942 | snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7); | ||
3943 | tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0); | ||
3944 | snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7); | ||
3945 | snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80); | ||
3946 | } | ||
3947 | #endif | ||
3948 | |||
3949 | board_config = snd_hda_check_board_config(codec, alc262_cfg_tbl); | ||
3950 | if (board_config < 0 || board_config >= ALC262_MODEL_LAST) { | ||
3951 | printk(KERN_INFO "hda_codec: Unknown model for ALC262, trying auto-probe from BIOS...\n"); | ||
3952 | board_config = ALC262_AUTO; | ||
3953 | } | ||
3954 | |||
3955 | if (board_config == ALC262_AUTO) { | ||
3956 | /* automatic parse from the BIOS config */ | ||
3957 | err = alc262_parse_auto_config(codec); | ||
3958 | if (err < 0) { | ||
3959 | alc_free(codec); | ||
3960 | return err; | ||
3961 | } else if (! err) { | ||
3962 | printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using base mode...\n"); | ||
3963 | board_config = ALC262_BASIC; | ||
3964 | } | ||
3965 | } | ||
3966 | |||
3967 | if (board_config != ALC262_AUTO) | ||
3968 | setup_preset(spec, &alc262_presets[board_config]); | ||
3969 | |||
3970 | spec->stream_name_analog = "ALC262 Analog"; | ||
3971 | spec->stream_analog_playback = &alc262_pcm_analog_playback; | ||
3972 | spec->stream_analog_capture = &alc262_pcm_analog_capture; | ||
3973 | |||
3974 | spec->stream_name_digital = "ALC262 Digital"; | ||
3975 | spec->stream_digital_playback = &alc262_pcm_digital_playback; | ||
3976 | spec->stream_digital_capture = &alc262_pcm_digital_capture; | ||
3977 | |||
3978 | if (! spec->adc_nids && spec->input_mux) { | ||
3979 | /* check whether NID 0x07 is valid */ | ||
3980 | unsigned int wcap = snd_hda_param_read(codec, 0x07, | ||
3981 | AC_PAR_AUDIO_WIDGET_CAP); | ||
3982 | wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */ | ||
3983 | if (wcap != AC_WID_AUD_IN) { | ||
3984 | spec->adc_nids = alc262_adc_nids_alt; | ||
3985 | spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids_alt); | ||
3986 | spec->mixers[spec->num_mixers] = alc262_capture_alt_mixer; | ||
3987 | spec->num_mixers++; | ||
3988 | } else { | ||
3989 | spec->adc_nids = alc262_adc_nids; | ||
3990 | spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids); | ||
3991 | spec->mixers[spec->num_mixers] = alc262_capture_mixer; | ||
3992 | spec->num_mixers++; | ||
3993 | } | ||
3994 | } | ||
2684 | 3995 | ||
2685 | codec->patch_ops = alc_patch_ops; | 3996 | codec->patch_ops = alc_patch_ops; |
3997 | if (board_config == ALC262_AUTO) | ||
3998 | codec->patch_ops.init = alc262_auto_init; | ||
3999 | |||
4000 | return 0; | ||
4001 | } | ||
4002 | |||
4003 | |||
4004 | /* | ||
4005 | * ALC861 channel source setting (2/6 channel selection for 3-stack) | ||
4006 | */ | ||
4007 | |||
4008 | /* | ||
4009 | * set the path ways for 2 channel output | ||
4010 | * need to set the codec line out and mic 1 pin widgets to inputs | ||
4011 | */ | ||
4012 | static struct hda_verb alc861_threestack_ch2_init[] = { | ||
4013 | /* set pin widget 1Ah (line in) for input */ | ||
4014 | { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
4015 | /* set pin widget 18h (mic1/2) for input, for mic also enable the vref */ | ||
4016 | { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
4017 | |||
4018 | { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c }, | ||
4019 | { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, //mic | ||
4020 | { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, //line in | ||
4021 | { } /* end */ | ||
4022 | }; | ||
4023 | /* | ||
4024 | * 6ch mode | ||
4025 | * need to set the codec line out and mic 1 pin widgets to outputs | ||
4026 | */ | ||
4027 | static struct hda_verb alc861_threestack_ch6_init[] = { | ||
4028 | /* set pin widget 1Ah (line in) for output (Back Surround)*/ | ||
4029 | { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
4030 | /* set pin widget 18h (mic1) for output (CLFE)*/ | ||
4031 | { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
4032 | |||
4033 | { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 }, | ||
4034 | { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 }, | ||
4035 | |||
4036 | { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, | ||
4037 | { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, //mic | ||
4038 | { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, //line in | ||
4039 | { } /* end */ | ||
4040 | }; | ||
4041 | |||
4042 | static struct hda_channel_mode alc861_threestack_modes[2] = { | ||
4043 | { 2, alc861_threestack_ch2_init }, | ||
4044 | { 6, alc861_threestack_ch6_init }, | ||
4045 | }; | ||
4046 | |||
4047 | /* patch-ALC861 */ | ||
4048 | |||
4049 | static struct snd_kcontrol_new alc861_base_mixer[] = { | ||
4050 | /* output mixer control */ | ||
4051 | HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), | ||
4052 | HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), | ||
4053 | HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), | ||
4054 | HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), | ||
4055 | HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), | ||
4056 | |||
4057 | /*Input mixer control */ | ||
4058 | /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT), | ||
4059 | HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */ | ||
4060 | HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), | ||
4061 | HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), | ||
4062 | HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT), | ||
4063 | HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT), | ||
4064 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), | ||
4065 | HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), | ||
4066 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), | ||
4067 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT), | ||
4068 | |||
4069 | /* Capture mixer control */ | ||
4070 | HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), | ||
4071 | HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), | ||
4072 | { | ||
4073 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4074 | .name = "Capture Source", | ||
4075 | .count = 1, | ||
4076 | .info = alc_mux_enum_info, | ||
4077 | .get = alc_mux_enum_get, | ||
4078 | .put = alc_mux_enum_put, | ||
4079 | }, | ||
4080 | { } /* end */ | ||
4081 | }; | ||
4082 | |||
4083 | static struct snd_kcontrol_new alc861_3ST_mixer[] = { | ||
4084 | /* output mixer control */ | ||
4085 | HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), | ||
4086 | HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), | ||
4087 | HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), | ||
4088 | HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), | ||
4089 | /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */ | ||
4090 | |||
4091 | /* Input mixer control */ | ||
4092 | /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT), | ||
4093 | HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */ | ||
4094 | HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), | ||
4095 | HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), | ||
4096 | HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT), | ||
4097 | HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT), | ||
4098 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), | ||
4099 | HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), | ||
4100 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), | ||
4101 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT), | ||
4102 | |||
4103 | /* Capture mixer control */ | ||
4104 | HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), | ||
4105 | HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), | ||
4106 | { | ||
4107 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4108 | .name = "Capture Source", | ||
4109 | .count = 1, | ||
4110 | .info = alc_mux_enum_info, | ||
4111 | .get = alc_mux_enum_get, | ||
4112 | .put = alc_mux_enum_put, | ||
4113 | }, | ||
4114 | { | ||
4115 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4116 | .name = "Channel Mode", | ||
4117 | .info = alc_ch_mode_info, | ||
4118 | .get = alc_ch_mode_get, | ||
4119 | .put = alc_ch_mode_put, | ||
4120 | .private_value = ARRAY_SIZE(alc861_threestack_modes), | ||
4121 | }, | ||
4122 | { } /* end */ | ||
4123 | }; | ||
4124 | |||
4125 | /* | ||
4126 | * generic initialization of ADC, input mixers and output mixers | ||
4127 | */ | ||
4128 | static struct hda_verb alc861_base_init_verbs[] = { | ||
4129 | /* | ||
4130 | * Unmute ADC0 and set the default input to mic-in | ||
4131 | */ | ||
4132 | /* port-A for surround (rear panel) */ | ||
4133 | { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
4134 | { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 }, | ||
4135 | /* port-B for mic-in (rear panel) with vref */ | ||
4136 | { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
4137 | /* port-C for line-in (rear panel) */ | ||
4138 | { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
4139 | /* port-D for Front */ | ||
4140 | { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
4141 | { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 }, | ||
4142 | /* port-E for HP out (front panel) */ | ||
4143 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | ||
4144 | /* route front PCM to HP */ | ||
4145 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01 }, | ||
4146 | /* port-F for mic-in (front panel) with vref */ | ||
4147 | { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
4148 | /* port-G for CLFE (rear panel) */ | ||
4149 | { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
4150 | { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 }, | ||
4151 | /* port-H for side (rear panel) */ | ||
4152 | { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
4153 | { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 }, | ||
4154 | /* CD-in */ | ||
4155 | { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
4156 | /* route front mic to ADC1*/ | ||
4157 | {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
4158 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4159 | |||
4160 | /* Unmute DAC0~3 & spdif out*/ | ||
4161 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4162 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4163 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4164 | {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4165 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4166 | |||
4167 | /* Unmute Mixer 14 (mic) 1c (Line in)*/ | ||
4168 | {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4169 | {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4170 | {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4171 | {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4172 | |||
4173 | /* Unmute Stereo Mixer 15 */ | ||
4174 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4175 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4176 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | ||
4177 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c }, //Output 0~12 step | ||
4178 | |||
4179 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4180 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4181 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4182 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4183 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4184 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4185 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4186 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4187 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, // hp used DAC 3 (Front) | ||
4188 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | ||
4189 | |||
4190 | { } | ||
4191 | }; | ||
2686 | 4192 | ||
4193 | static struct hda_verb alc861_threestack_init_verbs[] = { | ||
4194 | /* | ||
4195 | * Unmute ADC0 and set the default input to mic-in | ||
4196 | */ | ||
4197 | /* port-A for surround (rear panel) */ | ||
4198 | { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, | ||
4199 | /* port-B for mic-in (rear panel) with vref */ | ||
4200 | { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
4201 | /* port-C for line-in (rear panel) */ | ||
4202 | { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
4203 | /* port-D for Front */ | ||
4204 | { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
4205 | { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 }, | ||
4206 | /* port-E for HP out (front panel) */ | ||
4207 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | ||
4208 | /* route front PCM to HP */ | ||
4209 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01 }, | ||
4210 | /* port-F for mic-in (front panel) with vref */ | ||
4211 | { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
4212 | /* port-G for CLFE (rear panel) */ | ||
4213 | { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, | ||
4214 | /* port-H for side (rear panel) */ | ||
4215 | { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, | ||
4216 | /* CD-in */ | ||
4217 | { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
4218 | /* route front mic to ADC1*/ | ||
4219 | {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
4220 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4221 | /* Unmute DAC0~3 & spdif out*/ | ||
4222 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4223 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4224 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4225 | {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4226 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4227 | |||
4228 | /* Unmute Mixer 14 (mic) 1c (Line in)*/ | ||
4229 | {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4230 | {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4231 | {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4232 | {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4233 | |||
4234 | /* Unmute Stereo Mixer 15 */ | ||
4235 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4236 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4237 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | ||
4238 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c }, //Output 0~12 step | ||
4239 | |||
4240 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4241 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4242 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4243 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4244 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4245 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4246 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4247 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4248 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, // hp used DAC 3 (Front) | ||
4249 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | ||
4250 | { } | ||
4251 | }; | ||
4252 | /* | ||
4253 | * generic initialization of ADC, input mixers and output mixers | ||
4254 | */ | ||
4255 | static struct hda_verb alc861_auto_init_verbs[] = { | ||
4256 | /* | ||
4257 | * Unmute ADC0 and set the default input to mic-in | ||
4258 | */ | ||
4259 | // {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
4260 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4261 | |||
4262 | /* Unmute DAC0~3 & spdif out*/ | ||
4263 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4264 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4265 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4266 | {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
4267 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4268 | |||
4269 | /* Unmute Mixer 14 (mic) 1c (Line in)*/ | ||
4270 | {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4271 | {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4272 | {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4273 | {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4274 | |||
4275 | /* Unmute Stereo Mixer 15 */ | ||
4276 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4277 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4278 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | ||
4279 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, | ||
4280 | |||
4281 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4282 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4283 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4284 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4285 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4286 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4287 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
4288 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
4289 | |||
4290 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4291 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
4292 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | ||
4293 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, | ||
4294 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4295 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
4296 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | ||
4297 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, | ||
4298 | |||
4299 | {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, // set Mic 1 | ||
4300 | |||
4301 | { } | ||
4302 | }; | ||
4303 | |||
4304 | /* pcm configuration: identiacal with ALC880 */ | ||
4305 | #define alc861_pcm_analog_playback alc880_pcm_analog_playback | ||
4306 | #define alc861_pcm_analog_capture alc880_pcm_analog_capture | ||
4307 | #define alc861_pcm_digital_playback alc880_pcm_digital_playback | ||
4308 | #define alc861_pcm_digital_capture alc880_pcm_digital_capture | ||
4309 | |||
4310 | |||
4311 | #define ALC861_DIGOUT_NID 0x07 | ||
4312 | |||
4313 | static struct hda_channel_mode alc861_8ch_modes[1] = { | ||
4314 | { 8, NULL } | ||
4315 | }; | ||
4316 | |||
4317 | static hda_nid_t alc861_dac_nids[4] = { | ||
4318 | /* front, surround, clfe, side */ | ||
4319 | 0x03, 0x06, 0x05, 0x04 | ||
4320 | }; | ||
4321 | |||
4322 | static hda_nid_t alc861_adc_nids[1] = { | ||
4323 | /* ADC0-2 */ | ||
4324 | 0x08, | ||
4325 | }; | ||
4326 | |||
4327 | static struct hda_input_mux alc861_capture_source = { | ||
4328 | .num_items = 5, | ||
4329 | .items = { | ||
4330 | { "Mic", 0x0 }, | ||
4331 | { "Front Mic", 0x3 }, | ||
4332 | { "Line", 0x1 }, | ||
4333 | { "CD", 0x4 }, | ||
4334 | { "Mixer", 0x5 }, | ||
4335 | }, | ||
4336 | }; | ||
4337 | |||
4338 | /* fill in the dac_nids table from the parsed pin configuration */ | ||
4339 | static int alc861_auto_fill_dac_nids(struct alc_spec *spec, const struct auto_pin_cfg *cfg) | ||
4340 | { | ||
4341 | int i; | ||
4342 | hda_nid_t nid; | ||
4343 | |||
4344 | spec->multiout.dac_nids = spec->private_dac_nids; | ||
4345 | for (i = 0; i < cfg->line_outs; i++) { | ||
4346 | nid = cfg->line_out_pins[i]; | ||
4347 | if (nid) { | ||
4348 | if (i >= ARRAY_SIZE(alc861_dac_nids)) | ||
4349 | continue; | ||
4350 | spec->multiout.dac_nids[i] = alc861_dac_nids[i]; | ||
4351 | } | ||
4352 | } | ||
4353 | spec->multiout.num_dacs = cfg->line_outs; | ||
4354 | return 0; | ||
4355 | } | ||
4356 | |||
4357 | /* add playback controls from the parsed DAC table */ | ||
4358 | static int alc861_auto_create_multi_out_ctls(struct alc_spec *spec, | ||
4359 | const struct auto_pin_cfg *cfg) | ||
4360 | { | ||
4361 | char name[32]; | ||
4362 | static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" }; | ||
4363 | hda_nid_t nid; | ||
4364 | int i, idx, err; | ||
4365 | |||
4366 | for (i = 0; i < cfg->line_outs; i++) { | ||
4367 | nid = spec->multiout.dac_nids[i]; | ||
4368 | if (! nid) | ||
4369 | continue; | ||
4370 | if (nid == 0x05) { | ||
4371 | /* Center/LFE */ | ||
4372 | if ((err = add_control(spec, ALC_CTL_BIND_MUTE, "Center Playback Switch", | ||
4373 | HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT))) < 0) | ||
4374 | return err; | ||
4375 | if ((err = add_control(spec, ALC_CTL_BIND_MUTE, "LFE Playback Switch", | ||
4376 | HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0) | ||
4377 | return err; | ||
4378 | } else { | ||
4379 | for (idx = 0; idx < ARRAY_SIZE(alc861_dac_nids) - 1; idx++) | ||
4380 | if (nid == alc861_dac_nids[idx]) | ||
4381 | break; | ||
4382 | sprintf(name, "%s Playback Switch", chname[idx]); | ||
4383 | if ((err = add_control(spec, ALC_CTL_BIND_MUTE, name, | ||
4384 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) | ||
4385 | return err; | ||
4386 | } | ||
4387 | } | ||
4388 | return 0; | ||
4389 | } | ||
4390 | |||
4391 | static int alc861_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin) | ||
4392 | { | ||
4393 | int err; | ||
4394 | hda_nid_t nid; | ||
4395 | |||
4396 | if (! pin) | ||
4397 | return 0; | ||
4398 | |||
4399 | if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) { | ||
4400 | nid = 0x03; | ||
4401 | if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Headphone Playback Switch", | ||
4402 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) | ||
4403 | return err; | ||
4404 | spec->multiout.hp_nid = nid; | ||
4405 | } | ||
4406 | return 0; | ||
4407 | } | ||
4408 | |||
4409 | /* create playback/capture controls for input pins */ | ||
4410 | static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg) | ||
4411 | { | ||
4412 | static char *labels[AUTO_PIN_LAST] = { | ||
4413 | "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux" | ||
4414 | }; | ||
4415 | struct hda_input_mux *imux = &spec->private_imux; | ||
4416 | int i, err, idx, idx1; | ||
4417 | |||
4418 | for (i = 0; i < AUTO_PIN_LAST; i++) { | ||
4419 | switch(cfg->input_pins[i]) { | ||
4420 | case 0x0c: | ||
4421 | idx1 = 1; | ||
4422 | idx = 2; // Line In | ||
4423 | break; | ||
4424 | case 0x0f: | ||
4425 | idx1 = 2; | ||
4426 | idx = 2; // Line In | ||
4427 | break; | ||
4428 | case 0x0d: | ||
4429 | idx1 = 0; | ||
4430 | idx = 1; // Mic In | ||
4431 | break; | ||
4432 | case 0x10: | ||
4433 | idx1 = 3; | ||
4434 | idx = 1; // Mic In | ||
4435 | break; | ||
4436 | case 0x11: | ||
4437 | idx1 = 4; | ||
4438 | idx = 0; // CD | ||
4439 | break; | ||
4440 | default: | ||
4441 | continue; | ||
4442 | } | ||
4443 | |||
4444 | err = new_analog_input(spec, cfg->input_pins[i], labels[i], idx, 0x15); | ||
4445 | if (err < 0) | ||
4446 | return err; | ||
4447 | |||
4448 | imux->items[imux->num_items].label = labels[i]; | ||
4449 | imux->items[imux->num_items].index = idx1; | ||
4450 | imux->num_items++; | ||
4451 | } | ||
4452 | return 0; | ||
4453 | } | ||
4454 | |||
4455 | static struct snd_kcontrol_new alc861_capture_mixer[] = { | ||
4456 | HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), | ||
4457 | HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), | ||
4458 | |||
4459 | { | ||
4460 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
4461 | /* The multiple "Capture Source" controls confuse alsamixer | ||
4462 | * So call somewhat different.. | ||
4463 | *FIXME: the controls appear in the "playback" view! | ||
4464 | */ | ||
4465 | /* .name = "Capture Source", */ | ||
4466 | .name = "Input Source", | ||
4467 | .count = 1, | ||
4468 | .info = alc_mux_enum_info, | ||
4469 | .get = alc_mux_enum_get, | ||
4470 | .put = alc_mux_enum_put, | ||
4471 | }, | ||
4472 | { } /* end */ | ||
4473 | }; | ||
4474 | |||
4475 | static void alc861_auto_set_output_and_unmute(struct hda_codec *codec, hda_nid_t nid, | ||
4476 | int pin_type, int dac_idx) | ||
4477 | { | ||
4478 | /* set as output */ | ||
4479 | |||
4480 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); | ||
4481 | snd_hda_codec_write(codec, dac_idx, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); | ||
4482 | |||
4483 | } | ||
4484 | |||
4485 | static void alc861_auto_init_multi_out(struct hda_codec *codec) | ||
4486 | { | ||
4487 | struct alc_spec *spec = codec->spec; | ||
4488 | int i; | ||
4489 | |||
4490 | for (i = 0; i < spec->autocfg.line_outs; i++) { | ||
4491 | hda_nid_t nid = spec->autocfg.line_out_pins[i]; | ||
4492 | if (nid) | ||
4493 | alc861_auto_set_output_and_unmute(codec, nid, PIN_OUT, spec->multiout.dac_nids[i]); | ||
4494 | } | ||
4495 | } | ||
4496 | |||
4497 | static void alc861_auto_init_hp_out(struct hda_codec *codec) | ||
4498 | { | ||
4499 | struct alc_spec *spec = codec->spec; | ||
4500 | hda_nid_t pin; | ||
4501 | |||
4502 | pin = spec->autocfg.hp_pin; | ||
4503 | if (pin) /* connect to front */ | ||
4504 | alc861_auto_set_output_and_unmute(codec, pin, PIN_HP, spec->multiout.dac_nids[0]); | ||
4505 | } | ||
4506 | |||
4507 | static void alc861_auto_init_analog_input(struct hda_codec *codec) | ||
4508 | { | ||
4509 | struct alc_spec *spec = codec->spec; | ||
4510 | int i; | ||
4511 | |||
4512 | for (i = 0; i < AUTO_PIN_LAST; i++) { | ||
4513 | hda_nid_t nid = spec->autocfg.input_pins[i]; | ||
4514 | if ((nid>=0x0c) && (nid <=0x11)) { | ||
4515 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
4516 | i <= AUTO_PIN_FRONT_MIC ? PIN_VREF80 : PIN_IN); | ||
4517 | } | ||
4518 | } | ||
4519 | } | ||
4520 | |||
4521 | /* parse the BIOS configuration and set up the alc_spec */ | ||
4522 | /* return 1 if successful, 0 if the proper config is not found, or a negative error code */ | ||
4523 | static int alc861_parse_auto_config(struct hda_codec *codec) | ||
4524 | { | ||
4525 | struct alc_spec *spec = codec->spec; | ||
4526 | int err; | ||
4527 | static hda_nid_t alc861_ignore[] = { 0x1d, 0 }; | ||
4528 | |||
4529 | if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, | ||
4530 | alc861_ignore)) < 0) | ||
4531 | return err; | ||
4532 | if (! spec->autocfg.line_outs && ! spec->autocfg.speaker_pin && | ||
4533 | ! spec->autocfg.hp_pin) | ||
4534 | return 0; /* can't find valid BIOS pin config */ | ||
4535 | |||
4536 | if ((err = alc861_auto_fill_dac_nids(spec, &spec->autocfg)) < 0 || | ||
4537 | (err = alc861_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 || | ||
4538 | (err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pin)) < 0 || | ||
4539 | (err = alc861_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) | ||
4540 | return err; | ||
4541 | |||
4542 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; | ||
4543 | |||
4544 | if (spec->autocfg.dig_out_pin) | ||
4545 | spec->multiout.dig_out_nid = ALC861_DIGOUT_NID; | ||
4546 | |||
4547 | if (spec->kctl_alloc) | ||
4548 | spec->mixers[spec->num_mixers++] = spec->kctl_alloc; | ||
4549 | |||
4550 | spec->init_verbs[spec->num_init_verbs++] = alc861_auto_init_verbs; | ||
4551 | |||
4552 | spec->input_mux = &spec->private_imux; | ||
4553 | |||
4554 | spec->adc_nids = alc861_adc_nids; | ||
4555 | spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids); | ||
4556 | spec->mixers[spec->num_mixers] = alc861_capture_mixer; | ||
4557 | spec->num_mixers++; | ||
4558 | |||
4559 | return 1; | ||
4560 | } | ||
4561 | |||
4562 | /* init callback for auto-configuration model -- overriding the default init */ | ||
4563 | static int alc861_auto_init(struct hda_codec *codec) | ||
4564 | { | ||
4565 | alc_init(codec); | ||
4566 | alc861_auto_init_multi_out(codec); | ||
4567 | alc861_auto_init_hp_out(codec); | ||
4568 | alc861_auto_init_analog_input(codec); | ||
4569 | |||
4570 | return 0; | ||
4571 | } | ||
4572 | |||
4573 | |||
4574 | /* | ||
4575 | * configuration and preset | ||
4576 | */ | ||
4577 | static struct hda_board_config alc861_cfg_tbl[] = { | ||
4578 | { .modelname = "3stack", .config = ALC861_3ST }, | ||
4579 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xd600, .config = ALC861_3ST }, | ||
4580 | { .modelname = "3stack-dig", .config = ALC861_3ST_DIG }, | ||
4581 | { .modelname = "6stack-dig", .config = ALC861_6ST_DIG }, | ||
4582 | { .modelname = "auto", .config = ALC861_AUTO }, | ||
4583 | {} | ||
4584 | }; | ||
4585 | |||
4586 | static struct alc_config_preset alc861_presets[] = { | ||
4587 | [ALC861_3ST] = { | ||
4588 | .mixers = { alc861_3ST_mixer }, | ||
4589 | .init_verbs = { alc861_threestack_init_verbs }, | ||
4590 | .num_dacs = ARRAY_SIZE(alc861_dac_nids), | ||
4591 | .dac_nids = alc861_dac_nids, | ||
4592 | .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), | ||
4593 | .channel_mode = alc861_threestack_modes, | ||
4594 | .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), | ||
4595 | .adc_nids = alc861_adc_nids, | ||
4596 | .input_mux = &alc861_capture_source, | ||
4597 | }, | ||
4598 | [ALC861_3ST_DIG] = { | ||
4599 | .mixers = { alc861_base_mixer }, | ||
4600 | .init_verbs = { alc861_threestack_init_verbs }, | ||
4601 | .num_dacs = ARRAY_SIZE(alc861_dac_nids), | ||
4602 | .dac_nids = alc861_dac_nids, | ||
4603 | .dig_out_nid = ALC861_DIGOUT_NID, | ||
4604 | .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), | ||
4605 | .channel_mode = alc861_threestack_modes, | ||
4606 | .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), | ||
4607 | .adc_nids = alc861_adc_nids, | ||
4608 | .input_mux = &alc861_capture_source, | ||
4609 | }, | ||
4610 | [ALC861_6ST_DIG] = { | ||
4611 | .mixers = { alc861_base_mixer }, | ||
4612 | .init_verbs = { alc861_base_init_verbs }, | ||
4613 | .num_dacs = ARRAY_SIZE(alc861_dac_nids), | ||
4614 | .dac_nids = alc861_dac_nids, | ||
4615 | .dig_out_nid = ALC861_DIGOUT_NID, | ||
4616 | .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes), | ||
4617 | .channel_mode = alc861_8ch_modes, | ||
4618 | .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), | ||
4619 | .adc_nids = alc861_adc_nids, | ||
4620 | .input_mux = &alc861_capture_source, | ||
4621 | }, | ||
4622 | }; | ||
4623 | |||
4624 | |||
4625 | static int patch_alc861(struct hda_codec *codec) | ||
4626 | { | ||
4627 | struct alc_spec *spec; | ||
4628 | int board_config; | ||
4629 | int err; | ||
4630 | |||
4631 | spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); | ||
4632 | if (spec == NULL) | ||
4633 | return -ENOMEM; | ||
4634 | |||
4635 | codec->spec = spec; | ||
4636 | |||
4637 | board_config = snd_hda_check_board_config(codec, alc861_cfg_tbl); | ||
4638 | if (board_config < 0 || board_config >= ALC861_MODEL_LAST) { | ||
4639 | printk(KERN_INFO "hda_codec: Unknown model for ALC861, trying auto-probe from BIOS...\n"); | ||
4640 | board_config = ALC861_AUTO; | ||
4641 | } | ||
4642 | |||
4643 | if (board_config == ALC861_AUTO) { | ||
4644 | /* automatic parse from the BIOS config */ | ||
4645 | err = alc861_parse_auto_config(codec); | ||
4646 | if (err < 0) { | ||
4647 | alc_free(codec); | ||
4648 | return err; | ||
4649 | } else if (! err) { | ||
4650 | printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using base mode...\n"); | ||
4651 | board_config = ALC861_3ST_DIG; | ||
4652 | } | ||
4653 | } | ||
4654 | |||
4655 | if (board_config != ALC861_AUTO) | ||
4656 | setup_preset(spec, &alc861_presets[board_config]); | ||
4657 | |||
4658 | spec->stream_name_analog = "ALC861 Analog"; | ||
4659 | spec->stream_analog_playback = &alc861_pcm_analog_playback; | ||
4660 | spec->stream_analog_capture = &alc861_pcm_analog_capture; | ||
4661 | |||
4662 | spec->stream_name_digital = "ALC861 Digital"; | ||
4663 | spec->stream_digital_playback = &alc861_pcm_digital_playback; | ||
4664 | spec->stream_digital_capture = &alc861_pcm_digital_capture; | ||
4665 | |||
4666 | codec->patch_ops = alc_patch_ops; | ||
4667 | if (board_config == ALC861_AUTO) | ||
4668 | codec->patch_ops.init = alc861_auto_init; | ||
4669 | |||
2687 | return 0; | 4670 | return 0; |
2688 | } | 4671 | } |
2689 | 4672 | ||
@@ -2692,7 +4675,11 @@ static int patch_alc882(struct hda_codec *codec) | |||
2692 | */ | 4675 | */ |
2693 | struct hda_codec_preset snd_hda_preset_realtek[] = { | 4676 | struct hda_codec_preset snd_hda_preset_realtek[] = { |
2694 | { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 }, | 4677 | { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 }, |
4678 | { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 }, | ||
2695 | { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 }, | 4679 | { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 }, |
2696 | { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 }, | 4680 | { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 }, |
4681 | { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 }, | ||
4682 | { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 }, | ||
4683 | { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 }, | ||
2697 | {} /* terminator */ | 4684 | {} /* terminator */ |
2698 | }; | 4685 | }; |