[ALSA] hda: add PCM for 2nd ADC on ALC260
[linux-2.6/verdex.git] / sound / pci / hda / patch_realtek.c
blobc8fc6269b03c892e9c8e0e99cc2139737000c977
1 /*
2 * Universal Interface for Intel High Definition Audio Codec
4 * HD audio interface patch for ALC 260/880/882 codecs
6 * Copyright (c) 2004 Kailang Yang <kailang@realtek.com.tw>
7 * PeiSen Hou <pshou@realtek.com.tw>
8 * Takashi Iwai <tiwai@suse.de>
10 * This driver is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This driver is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include <sound/driver.h>
26 #include <linux/init.h>
27 #include <linux/delay.h>
28 #include <linux/slab.h>
29 #include <linux/pci.h>
30 #include <sound/core.h>
31 #include "hda_codec.h"
32 #include "hda_local.h"
35 /* ALC880 board config type */
36 enum {
37 ALC880_3ST,
38 ALC880_3ST_DIG,
39 ALC880_5ST,
40 ALC880_5ST_DIG,
41 ALC880_W810,
42 ALC880_Z71V,
43 ALC880_6ST,
44 ALC880_6ST_DIG,
45 ALC880_F1734,
46 ALC880_ASUS,
47 ALC880_ASUS_DIG,
48 ALC880_ASUS_W1V,
49 ALC880_ASUS_DIG2,
50 ALC880_UNIWILL_DIG,
51 ALC880_CLEVO,
52 ALC880_TCL_S700,
53 #ifdef CONFIG_SND_DEBUG
54 ALC880_TEST,
55 #endif
56 ALC880_AUTO,
57 ALC880_MODEL_LAST /* last tag */
60 /* ALC260 models */
61 enum {
62 ALC260_BASIC,
63 ALC260_HP,
64 ALC260_HP_3013,
65 ALC260_FUJITSU_S702X,
66 ALC260_AUTO,
67 ALC260_MODEL_LAST /* last tag */
70 /* ALC262 models */
71 enum {
72 ALC262_BASIC,
73 ALC262_AUTO,
74 ALC262_MODEL_LAST /* last tag */
77 /* ALC861 models */
78 enum {
79 ALC861_3ST,
80 ALC861_3ST_DIG,
81 ALC861_6ST_DIG,
82 ALC861_AUTO,
83 ALC861_MODEL_LAST,
86 /* ALC882 models */
87 enum {
88 ALC882_3ST_DIG,
89 ALC882_6ST_DIG,
90 ALC882_AUTO,
91 ALC882_MODEL_LAST,
94 /* for GPIO Poll */
95 #define GPIO_MASK 0x03
97 struct alc_spec {
98 /* codec parameterization */
99 struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
100 unsigned int num_mixers;
102 const struct hda_verb *init_verbs[5]; /* initialization verbs
103 * don't forget NULL termination!
105 unsigned int num_init_verbs;
107 char *stream_name_analog; /* analog PCM stream */
108 struct hda_pcm_stream *stream_analog_playback;
109 struct hda_pcm_stream *stream_analog_capture;
111 char *stream_name_digital; /* digital PCM stream */
112 struct hda_pcm_stream *stream_digital_playback;
113 struct hda_pcm_stream *stream_digital_capture;
115 /* playback */
116 struct hda_multi_out multiout; /* playback set-up
117 * max_channels, dacs must be set
118 * dig_out_nid and hp_nid are optional
121 /* capture */
122 unsigned int num_adc_nids;
123 hda_nid_t *adc_nids;
124 hda_nid_t dig_in_nid; /* digital-in NID; optional */
126 /* capture source */
127 const struct hda_input_mux *input_mux;
128 unsigned int cur_mux[3];
130 /* channel model */
131 const struct hda_channel_mode *channel_mode;
132 int num_channel_mode;
134 /* PCM information */
135 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
137 /* dynamic controls, init_verbs and input_mux */
138 struct auto_pin_cfg autocfg;
139 unsigned int num_kctl_alloc, num_kctl_used;
140 struct snd_kcontrol_new *kctl_alloc;
141 struct hda_input_mux private_imux;
142 hda_nid_t private_dac_nids[5];
146 * configuration template - to be copied to the spec instance
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;
165 * input MUX handling
167 static int alc_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
169 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
170 struct alc_spec *spec = codec->spec;
171 return snd_hda_input_mux_info(spec->input_mux, uinfo);
174 static int alc_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
176 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
177 struct alc_spec *spec = codec->spec;
178 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
180 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
181 return 0;
184 static int alc_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
186 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
187 struct alc_spec *spec = codec->spec;
188 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
189 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
190 spec->adc_nids[adc_idx], &spec->cur_mux[adc_idx]);
195 * channel mode setting
197 static int alc_ch_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
199 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
200 struct alc_spec *spec = codec->spec;
201 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
202 spec->num_channel_mode);
205 static int alc_ch_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
207 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
208 struct alc_spec *spec = codec->spec;
209 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
210 spec->num_channel_mode, spec->multiout.max_channels);
213 static int alc_ch_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
215 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
216 struct alc_spec *spec = codec->spec;
217 return snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
218 spec->num_channel_mode, &spec->multiout.max_channels);
222 * Control the mode of pin widget settings via the mixer. "pc" is used
223 * instead of "%" to avoid consequences of accidently treating the % as
224 * being part of a format specifier. Maximum allowed length of a value is
225 * 63 characters plus NULL terminator.
227 static char *alc_pin_mode_names[] = {
228 "Line in", "Mic 80pc bias", "Mic 50pc bias",
229 "Line out", "Headphone out",
231 static unsigned char alc_pin_mode_values[] = {
232 PIN_IN, PIN_VREF80, PIN_VREF50, PIN_OUT, PIN_HP,
234 /* The control can present all 5 options, or it can limit the options based
235 * in the pin being assumed to be exclusively an input or an output pin.
237 #define ALC_PIN_DIR_IN 0x00
238 #define ALC_PIN_DIR_OUT 0x01
239 #define ALC_PIN_DIR_INOUT 0x02
241 /* Info about the pin modes supported by the three different pin directions.
242 * For each direction the minimum and maximum values are given.
244 static signed char alc_pin_mode_dir_info[3][2] = {
245 { 0, 2 }, /* ALC_PIN_DIR_IN */
246 { 3, 4 }, /* ALC_PIN_DIR_OUT */
247 { 0, 4 }, /* ALC_PIN_DIR_INOUT */
249 #define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0])
250 #define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1])
251 #define alc_pin_mode_n_items(_dir) \
252 (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1)
254 static int alc_pin_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
256 unsigned int item_num = uinfo->value.enumerated.item;
257 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
259 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
260 uinfo->count = 1;
261 uinfo->value.enumerated.items = alc_pin_mode_n_items(dir);
263 if (item_num<alc_pin_mode_min(dir) || item_num>alc_pin_mode_max(dir))
264 item_num = alc_pin_mode_min(dir);
265 strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]);
266 return 0;
269 static int alc_pin_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
271 unsigned int i;
272 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
273 hda_nid_t nid = kcontrol->private_value & 0xffff;
274 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
275 long *valp = ucontrol->value.integer.value;
276 unsigned int pinctl = snd_hda_codec_read(codec,nid,0,AC_VERB_GET_PIN_WIDGET_CONTROL,0x00);
278 /* Find enumerated value for current pinctl setting */
279 i = alc_pin_mode_min(dir);
280 while (alc_pin_mode_values[i]!=pinctl && i<=alc_pin_mode_max(dir))
281 i++;
282 *valp = i<=alc_pin_mode_max(dir)?i:alc_pin_mode_min(dir);
283 return 0;
286 static int alc_pin_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
288 signed int change;
289 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
290 hda_nid_t nid = kcontrol->private_value & 0xffff;
291 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
292 long val = *ucontrol->value.integer.value;
293 unsigned int pinctl = snd_hda_codec_read(codec,nid,0,AC_VERB_GET_PIN_WIDGET_CONTROL,0x00);
295 if (val<alc_pin_mode_min(dir) || val>alc_pin_mode_max(dir))
296 val = alc_pin_mode_min(dir);
298 change = pinctl != alc_pin_mode_values[val];
299 if (change)
300 snd_hda_codec_write(codec,nid,0,AC_VERB_SET_PIN_WIDGET_CONTROL,
301 alc_pin_mode_values[val]);
302 return change;
305 #define ALC_PIN_MODE(xname, nid, dir) \
306 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
307 .info = alc_pin_mode_info, \
308 .get = alc_pin_mode_get, \
309 .put = alc_pin_mode_put, \
310 .private_value = nid | (dir<<16) }
313 * set up from the preset table
315 static void setup_preset(struct alc_spec *spec, const struct alc_config_preset *preset)
317 int i;
319 for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
320 spec->mixers[spec->num_mixers++] = preset->mixers[i];
321 for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i]; i++)
322 spec->init_verbs[spec->num_init_verbs++] = preset->init_verbs[i];
324 spec->channel_mode = preset->channel_mode;
325 spec->num_channel_mode = preset->num_channel_mode;
327 spec->multiout.max_channels = spec->channel_mode[0].channels;
329 spec->multiout.num_dacs = preset->num_dacs;
330 spec->multiout.dac_nids = preset->dac_nids;
331 spec->multiout.dig_out_nid = preset->dig_out_nid;
332 spec->multiout.hp_nid = preset->hp_nid;
334 spec->input_mux = preset->input_mux;
336 spec->num_adc_nids = preset->num_adc_nids;
337 spec->adc_nids = preset->adc_nids;
338 spec->dig_in_nid = preset->dig_in_nid;
342 * ALC880 3-stack model
344 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
345 * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18, F-Mic = 0x1b
346 * HP = 0x19
349 static hda_nid_t alc880_dac_nids[4] = {
350 /* front, rear, clfe, rear_surr */
351 0x02, 0x05, 0x04, 0x03
354 static hda_nid_t alc880_adc_nids[3] = {
355 /* ADC0-2 */
356 0x07, 0x08, 0x09,
359 /* The datasheet says the node 0x07 is connected from inputs,
360 * but it shows zero connection in the real implementation on some devices.
361 * Note: this is a 915GAV bug, fixed on 915GLV
363 static hda_nid_t alc880_adc_nids_alt[2] = {
364 /* ADC1-2 */
365 0x08, 0x09,
368 #define ALC880_DIGOUT_NID 0x06
369 #define ALC880_DIGIN_NID 0x0a
371 static struct hda_input_mux alc880_capture_source = {
372 .num_items = 4,
373 .items = {
374 { "Mic", 0x0 },
375 { "Front Mic", 0x3 },
376 { "Line", 0x2 },
377 { "CD", 0x4 },
381 /* channel source setting (2/6 channel selection for 3-stack) */
382 /* 2ch mode */
383 static struct hda_verb alc880_threestack_ch2_init[] = {
384 /* set line-in to input, mute it */
385 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
386 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
387 /* set mic-in to input vref 80%, mute it */
388 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
389 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
390 { } /* end */
393 /* 6ch mode */
394 static struct hda_verb alc880_threestack_ch6_init[] = {
395 /* set line-in to output, unmute it */
396 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
397 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
398 /* set mic-in to output, unmute it */
399 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
400 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
401 { } /* end */
404 static struct hda_channel_mode alc880_threestack_modes[2] = {
405 { 2, alc880_threestack_ch2_init },
406 { 6, alc880_threestack_ch6_init },
409 static struct snd_kcontrol_new alc880_three_stack_mixer[] = {
410 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
411 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
412 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
413 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
414 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
415 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
416 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
417 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
418 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
419 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
420 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
421 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
422 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
423 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
424 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
425 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
426 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
427 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
428 HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
430 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
431 .name = "Channel Mode",
432 .info = alc_ch_mode_info,
433 .get = alc_ch_mode_get,
434 .put = alc_ch_mode_put,
436 { } /* end */
439 /* capture mixer elements */
440 static struct snd_kcontrol_new alc880_capture_mixer[] = {
441 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
442 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
443 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
444 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
445 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
446 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
448 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
449 /* The multiple "Capture Source" controls confuse alsamixer
450 * So call somewhat different..
451 * FIXME: the controls appear in the "playback" view!
453 /* .name = "Capture Source", */
454 .name = "Input Source",
455 .count = 3,
456 .info = alc_mux_enum_info,
457 .get = alc_mux_enum_get,
458 .put = alc_mux_enum_put,
460 { } /* end */
463 /* capture mixer elements (in case NID 0x07 not available) */
464 static struct snd_kcontrol_new alc880_capture_alt_mixer[] = {
465 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
466 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
467 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
468 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
470 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
471 /* The multiple "Capture Source" controls confuse alsamixer
472 * So call somewhat different..
473 * FIXME: the controls appear in the "playback" view!
475 /* .name = "Capture Source", */
476 .name = "Input Source",
477 .count = 2,
478 .info = alc_mux_enum_info,
479 .get = alc_mux_enum_get,
480 .put = alc_mux_enum_put,
482 { } /* end */
488 * ALC880 5-stack model
490 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d), Side = 0x02 (0xd)
491 * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
492 * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
495 /* additional mixers to alc880_three_stack_mixer */
496 static struct snd_kcontrol_new alc880_five_stack_mixer[] = {
497 HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
498 HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
499 { } /* end */
502 /* channel source setting (6/8 channel selection for 5-stack) */
503 /* 6ch mode */
504 static struct hda_verb alc880_fivestack_ch6_init[] = {
505 /* set line-in to input, mute it */
506 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
507 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
508 { } /* end */
511 /* 8ch mode */
512 static struct hda_verb alc880_fivestack_ch8_init[] = {
513 /* set line-in to output, unmute it */
514 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
515 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
516 { } /* end */
519 static struct hda_channel_mode alc880_fivestack_modes[2] = {
520 { 6, alc880_fivestack_ch6_init },
521 { 8, alc880_fivestack_ch8_init },
526 * ALC880 6-stack model
528 * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e), Side = 0x05 (0x0f)
529 * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
530 * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
533 static hda_nid_t alc880_6st_dac_nids[4] = {
534 /* front, rear, clfe, rear_surr */
535 0x02, 0x03, 0x04, 0x05
538 static struct hda_input_mux alc880_6stack_capture_source = {
539 .num_items = 4,
540 .items = {
541 { "Mic", 0x0 },
542 { "Front Mic", 0x1 },
543 { "Line", 0x2 },
544 { "CD", 0x4 },
548 /* fixed 8-channels */
549 static struct hda_channel_mode alc880_sixstack_modes[1] = {
550 { 8, NULL },
553 static struct snd_kcontrol_new alc880_six_stack_mixer[] = {
554 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
555 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
556 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
557 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
558 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
559 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
560 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
561 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
562 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
563 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
564 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
565 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
566 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
567 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
568 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
569 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
570 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
571 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
572 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
573 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
575 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
576 .name = "Channel Mode",
577 .info = alc_ch_mode_info,
578 .get = alc_ch_mode_get,
579 .put = alc_ch_mode_put,
581 { } /* end */
586 * ALC880 W810 model
588 * W810 has rear IO for:
589 * Front (DAC 02)
590 * Surround (DAC 03)
591 * Center/LFE (DAC 04)
592 * Digital out (06)
594 * The system also has a pair of internal speakers, and a headphone jack.
595 * These are both connected to Line2 on the codec, hence to DAC 02.
597 * There is a variable resistor to control the speaker or headphone
598 * volume. This is a hardware-only device without a software API.
600 * Plugging headphones in will disable the internal speakers. This is
601 * implemented in hardware, not via the driver using jack sense. In
602 * a similar fashion, plugging into the rear socket marked "front" will
603 * disable both the speakers and headphones.
605 * For input, there's a microphone jack, and an "audio in" jack.
606 * These may not do anything useful with this driver yet, because I
607 * haven't setup any initialization verbs for these yet...
610 static hda_nid_t alc880_w810_dac_nids[3] = {
611 /* front, rear/surround, clfe */
612 0x02, 0x03, 0x04
615 /* fixed 6 channels */
616 static struct hda_channel_mode alc880_w810_modes[1] = {
617 { 6, NULL }
620 /* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
621 static struct snd_kcontrol_new alc880_w810_base_mixer[] = {
622 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
623 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
624 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
625 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
626 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
627 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
628 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
629 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
630 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
631 { } /* end */
636 * Z710V model
638 * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
639 * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?), Line = 0x1a
642 static hda_nid_t alc880_z71v_dac_nids[1] = {
643 0x02
645 #define ALC880_Z71V_HP_DAC 0x03
647 /* fixed 2 channels */
648 static struct hda_channel_mode alc880_2_jack_modes[1] = {
649 { 2, NULL }
652 static struct snd_kcontrol_new alc880_z71v_mixer[] = {
653 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
654 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
655 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
656 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
657 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
658 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
659 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
660 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
661 { } /* end */
665 /* FIXME! */
667 * ALC880 F1734 model
669 * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
670 * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
673 static hda_nid_t alc880_f1734_dac_nids[1] = {
674 0x03
676 #define ALC880_F1734_HP_DAC 0x02
678 static struct snd_kcontrol_new alc880_f1734_mixer[] = {
679 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
680 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
681 HDA_CODEC_VOLUME("Internal Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
682 HDA_BIND_MUTE("Internal Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
683 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
684 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
685 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
686 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
687 { } /* end */
691 /* FIXME! */
693 * ALC880 ASUS model
695 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
696 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
697 * Mic = 0x18, Line = 0x1a
700 #define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */
701 #define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */
703 static struct snd_kcontrol_new alc880_asus_mixer[] = {
704 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
705 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
706 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
707 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
708 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
709 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
710 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
711 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
712 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
713 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
714 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
715 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
716 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
717 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
719 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
720 .name = "Channel Mode",
721 .info = alc_ch_mode_info,
722 .get = alc_ch_mode_get,
723 .put = alc_ch_mode_put,
725 { } /* end */
728 /* FIXME! */
730 * ALC880 ASUS W1V model
732 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
733 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
734 * Mic = 0x18, Line = 0x1a, Line2 = 0x1b
737 /* additional mixers to alc880_asus_mixer */
738 static struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
739 HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
740 HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
741 { } /* end */
744 /* additional mixers to alc880_asus_mixer */
745 static struct snd_kcontrol_new alc880_pcbeep_mixer[] = {
746 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
747 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
748 { } /* end */
751 /* TCL S700 */
752 static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
753 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
754 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
755 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
756 HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT),
757 HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT),
758 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT),
759 HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT),
760 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
761 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
763 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
764 /* The multiple "Capture Source" controls confuse alsamixer
765 * So call somewhat different..
766 * FIXME: the controls appear in the "playback" view!
768 /* .name = "Capture Source", */
769 .name = "Input Source",
770 .count = 1,
771 .info = alc_mux_enum_info,
772 .get = alc_mux_enum_get,
773 .put = alc_mux_enum_put,
775 { } /* end */
779 * build control elements
781 static int alc_build_controls(struct hda_codec *codec)
783 struct alc_spec *spec = codec->spec;
784 int err;
785 int i;
787 for (i = 0; i < spec->num_mixers; i++) {
788 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
789 if (err < 0)
790 return err;
793 if (spec->multiout.dig_out_nid) {
794 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
795 if (err < 0)
796 return err;
798 if (spec->dig_in_nid) {
799 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
800 if (err < 0)
801 return err;
803 return 0;
808 * initialize the codec volumes, etc
812 * generic initialization of ADC, input mixers and output mixers
814 static struct hda_verb alc880_volume_init_verbs[] = {
816 * Unmute ADC0-2 and set the default input to mic-in
818 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
819 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
820 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
821 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
822 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
823 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
825 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
826 * mixer widget
827 * Note: PASD motherboards uses the Line In 2 as the input for front panel
828 * mic (mic 2)
830 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
831 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
832 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
833 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
834 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
835 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
838 * Set up output mixers (0x0c - 0x0f)
840 /* set vol=0 to output mixers */
841 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
842 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
843 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
844 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
845 /* set up input amps for analog loopback */
846 /* Amp Indices: DAC = 0, mixer = 1 */
847 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
848 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
849 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
850 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
851 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
852 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
853 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
854 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
860 * 3-stack pin configuration:
861 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
863 static struct hda_verb alc880_pin_3stack_init_verbs[] = {
865 * preset connection lists of input pins
866 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
868 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
869 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
870 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
873 * Set pin mode and muting
875 /* set front pin widgets 0x14 for output */
876 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
877 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
878 /* Mic1 (rear panel) pin widget for input and vref at 80% */
879 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
880 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
881 /* Mic2 (as headphone out) for HP output */
882 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
883 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
884 /* Line In pin widget for input */
885 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
886 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
887 /* Line2 (as front mic) pin widget for input and vref at 80% */
888 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
889 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
890 /* CD pin widget for input */
891 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
897 * 5-stack pin configuration:
898 * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
899 * line-in/side = 0x1a, f-mic = 0x1b
901 static struct hda_verb alc880_pin_5stack_init_verbs[] = {
903 * preset connection lists of input pins
904 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
906 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
907 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
910 * Set pin mode and muting
912 /* set pin widgets 0x14-0x17 for output */
913 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
914 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
915 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
916 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
917 /* unmute pins for output (no gain on this amp) */
918 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
919 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
920 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
921 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
923 /* Mic1 (rear panel) pin widget for input and vref at 80% */
924 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
925 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
926 /* Mic2 (as headphone out) for HP output */
927 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
928 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
929 /* Line In pin widget for input */
930 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
931 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
932 /* Line2 (as front mic) pin widget for input and vref at 80% */
933 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
934 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
935 /* CD pin widget for input */
936 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
942 * W810 pin configuration:
943 * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
945 static struct hda_verb alc880_pin_w810_init_verbs[] = {
946 /* hphone/speaker input selector: front DAC */
947 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
949 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
950 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
951 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
952 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
953 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
954 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
956 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
957 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
963 * Z71V pin configuration:
964 * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
966 static struct hda_verb alc880_pin_z71v_init_verbs[] = {
967 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
968 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
969 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
970 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
972 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
973 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
974 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
975 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
981 * 6-stack pin configuration:
982 * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18, f-mic = 0x19,
983 * line = 0x1a, HP = 0x1b
985 static struct hda_verb alc880_pin_6stack_init_verbs[] = {
986 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
988 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
989 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
990 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
991 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
992 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
993 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
994 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
995 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
997 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
998 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
999 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1000 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1001 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1002 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1003 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1004 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1005 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1010 /* FIXME! */
1012 * F1734 pin configuration:
1013 * HP = 0x14, speaker-out = 0x15, mic = 0x18
1015 static struct hda_verb alc880_pin_f1734_init_verbs[] = {
1016 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
1017 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
1018 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
1019 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
1021 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1022 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1023 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1024 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1026 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1027 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1028 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1029 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1030 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1031 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1032 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1033 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1034 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1039 /* FIXME! */
1041 * ASUS pin configuration:
1042 * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
1044 static struct hda_verb alc880_pin_asus_init_verbs[] = {
1045 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
1046 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
1047 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
1048 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
1050 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1051 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1052 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1053 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1054 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1055 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1056 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1057 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1059 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1060 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1061 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1062 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1063 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1064 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1065 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1066 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1067 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1072 /* Enable GPIO mask and set output */
1073 static struct hda_verb alc880_gpio1_init_verbs[] = {
1074 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
1075 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
1076 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
1081 /* Enable GPIO mask and set output */
1082 static struct hda_verb alc880_gpio2_init_verbs[] = {
1083 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
1084 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
1085 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
1090 /* Clevo m520g init */
1091 static struct hda_verb alc880_pin_clevo_init_verbs[] = {
1092 /* headphone output */
1093 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
1094 /* line-out */
1095 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1096 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1097 /* Line-in */
1098 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1099 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1100 /* CD */
1101 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1102 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1103 /* Mic1 (rear panel) */
1104 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1105 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1106 /* Mic2 (front panel) */
1107 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1108 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1109 /* headphone */
1110 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1111 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1112 /* change to EAPD mode */
1113 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
1114 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
1119 static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
1120 /* Headphone output */
1121 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1122 /* Front output*/
1123 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1124 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
1126 /* Line In pin widget for input */
1127 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1128 /* CD pin widget for input */
1129 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1130 /* Mic1 (rear panel) pin widget for input and vref at 80% */
1131 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1133 /* change to EAPD mode */
1134 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
1135 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
1143 static int alc_init(struct hda_codec *codec)
1145 struct alc_spec *spec = codec->spec;
1146 unsigned int i;
1148 for (i = 0; i < spec->num_init_verbs; i++)
1149 snd_hda_sequence_write(codec, spec->init_verbs[i]);
1150 return 0;
1153 #ifdef CONFIG_PM
1155 * resume
1157 static int alc_resume(struct hda_codec *codec)
1159 struct alc_spec *spec = codec->spec;
1160 int i;
1162 alc_init(codec);
1163 for (i = 0; i < spec->num_mixers; i++)
1164 snd_hda_resume_ctls(codec, spec->mixers[i]);
1165 if (spec->multiout.dig_out_nid)
1166 snd_hda_resume_spdif_out(codec);
1167 if (spec->dig_in_nid)
1168 snd_hda_resume_spdif_in(codec);
1170 return 0;
1172 #endif
1175 * Analog playback callbacks
1177 static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
1178 struct hda_codec *codec,
1179 struct snd_pcm_substream *substream)
1181 struct alc_spec *spec = codec->spec;
1182 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
1185 static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1186 struct hda_codec *codec,
1187 unsigned int stream_tag,
1188 unsigned int format,
1189 struct snd_pcm_substream *substream)
1191 struct alc_spec *spec = codec->spec;
1192 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag,
1193 format, substream);
1196 static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
1197 struct hda_codec *codec,
1198 struct snd_pcm_substream *substream)
1200 struct alc_spec *spec = codec->spec;
1201 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
1205 * Digital out
1207 static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
1208 struct hda_codec *codec,
1209 struct snd_pcm_substream *substream)
1211 struct alc_spec *spec = codec->spec;
1212 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
1215 static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
1216 struct hda_codec *codec,
1217 struct snd_pcm_substream *substream)
1219 struct alc_spec *spec = codec->spec;
1220 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
1224 * Analog capture
1226 static int alc880_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
1227 struct hda_codec *codec,
1228 unsigned int stream_tag,
1229 unsigned int format,
1230 struct snd_pcm_substream *substream)
1232 struct alc_spec *spec = codec->spec;
1234 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
1235 stream_tag, 0, format);
1236 return 0;
1239 static int alc880_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
1240 struct hda_codec *codec,
1241 struct snd_pcm_substream *substream)
1243 struct alc_spec *spec = codec->spec;
1245 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0);
1246 return 0;
1252 static struct hda_pcm_stream alc880_pcm_analog_playback = {
1253 .substreams = 1,
1254 .channels_min = 2,
1255 .channels_max = 8,
1256 /* NID is set in alc_build_pcms */
1257 .ops = {
1258 .open = alc880_playback_pcm_open,
1259 .prepare = alc880_playback_pcm_prepare,
1260 .cleanup = alc880_playback_pcm_cleanup
1264 static struct hda_pcm_stream alc880_pcm_analog_capture = {
1265 .substreams = 2,
1266 .channels_min = 2,
1267 .channels_max = 2,
1268 /* NID is set in alc_build_pcms */
1269 .ops = {
1270 .prepare = alc880_capture_pcm_prepare,
1271 .cleanup = alc880_capture_pcm_cleanup
1275 static struct hda_pcm_stream alc880_pcm_digital_playback = {
1276 .substreams = 1,
1277 .channels_min = 2,
1278 .channels_max = 2,
1279 /* NID is set in alc_build_pcms */
1280 .ops = {
1281 .open = alc880_dig_playback_pcm_open,
1282 .close = alc880_dig_playback_pcm_close
1286 static struct hda_pcm_stream alc880_pcm_digital_capture = {
1287 .substreams = 1,
1288 .channels_min = 2,
1289 .channels_max = 2,
1290 /* NID is set in alc_build_pcms */
1293 /* Used by alc_build_pcms to flag that a PCM has no playback stream */
1294 static struct hda_pcm_stream alc_pcm_null_playback = {
1295 .substreams = 0,
1296 .channels_min = 0,
1297 .channels_max = 0,
1300 static int alc_build_pcms(struct hda_codec *codec)
1302 struct alc_spec *spec = codec->spec;
1303 struct hda_pcm *info = spec->pcm_rec;
1304 int i;
1306 codec->num_pcms = 1;
1307 codec->pcm_info = info;
1309 info->name = spec->stream_name_analog;
1310 if (spec->stream_analog_playback) {
1311 snd_assert(spec->multiout.dac_nids, return -EINVAL);
1312 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
1313 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
1315 if (spec->stream_analog_capture) {
1316 snd_assert(spec->adc_nids, return -EINVAL);
1317 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
1318 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
1321 if (spec->channel_mode) {
1322 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
1323 for (i = 0; i < spec->num_channel_mode; i++) {
1324 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
1325 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
1330 /* If the use of more than one ADC is requested for the current
1331 * model, configure a second analog capture-only PCM.
1333 if (spec->num_adc_nids > 1) {
1334 codec->num_pcms++;
1335 info++;
1336 info->name = spec->stream_name_analog;
1337 /* No playback stream for second PCM */
1338 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = alc_pcm_null_playback;
1339 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
1340 if (spec->stream_analog_capture) {
1341 snd_assert(spec->adc_nids, return -EINVAL);
1342 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
1343 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[1];
1347 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
1348 codec->num_pcms++;
1349 info++;
1350 info->name = spec->stream_name_digital;
1351 if (spec->multiout.dig_out_nid &&
1352 spec->stream_digital_playback) {
1353 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
1354 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
1356 if (spec->dig_in_nid &&
1357 spec->stream_digital_capture) {
1358 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
1359 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
1363 return 0;
1366 static void alc_free(struct hda_codec *codec)
1368 struct alc_spec *spec = codec->spec;
1369 unsigned int i;
1371 if (! spec)
1372 return;
1374 if (spec->kctl_alloc) {
1375 for (i = 0; i < spec->num_kctl_used; i++)
1376 kfree(spec->kctl_alloc[i].name);
1377 kfree(spec->kctl_alloc);
1379 kfree(spec);
1384 static struct hda_codec_ops alc_patch_ops = {
1385 .build_controls = alc_build_controls,
1386 .build_pcms = alc_build_pcms,
1387 .init = alc_init,
1388 .free = alc_free,
1389 #ifdef CONFIG_PM
1390 .resume = alc_resume,
1391 #endif
1396 * Test configuration for debugging
1398 * Almost all inputs/outputs are enabled. I/O pins can be configured via
1399 * enum controls.
1401 #ifdef CONFIG_SND_DEBUG
1402 static hda_nid_t alc880_test_dac_nids[4] = {
1403 0x02, 0x03, 0x04, 0x05
1406 static struct hda_input_mux alc880_test_capture_source = {
1407 .num_items = 5,
1408 .items = {
1409 { "In-1", 0x0 },
1410 { "In-2", 0x1 },
1411 { "In-3", 0x2 },
1412 { "In-4", 0x3 },
1413 { "CD", 0x4 },
1417 static struct hda_channel_mode alc880_test_modes[4] = {
1418 { 2, NULL },
1419 { 4, NULL },
1420 { 6, NULL },
1421 { 8, NULL },
1424 static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
1426 static char *texts[] = {
1427 "N/A", "Line Out", "HP Out",
1428 "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
1430 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1431 uinfo->count = 1;
1432 uinfo->value.enumerated.items = 8;
1433 if (uinfo->value.enumerated.item >= 8)
1434 uinfo->value.enumerated.item = 7;
1435 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1436 return 0;
1439 static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1441 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1442 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
1443 unsigned int pin_ctl, item = 0;
1445 pin_ctl = snd_hda_codec_read(codec, nid, 0,
1446 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
1447 if (pin_ctl & AC_PINCTL_OUT_EN) {
1448 if (pin_ctl & AC_PINCTL_HP_EN)
1449 item = 2;
1450 else
1451 item = 1;
1452 } else if (pin_ctl & AC_PINCTL_IN_EN) {
1453 switch (pin_ctl & AC_PINCTL_VREFEN) {
1454 case AC_PINCTL_VREF_HIZ: item = 3; break;
1455 case AC_PINCTL_VREF_50: item = 4; break;
1456 case AC_PINCTL_VREF_GRD: item = 5; break;
1457 case AC_PINCTL_VREF_80: item = 6; break;
1458 case AC_PINCTL_VREF_100: item = 7; break;
1461 ucontrol->value.enumerated.item[0] = item;
1462 return 0;
1465 static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1467 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1468 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
1469 static unsigned int ctls[] = {
1470 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
1471 AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
1472 AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
1473 AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
1474 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
1475 AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
1477 unsigned int old_ctl, new_ctl;
1479 old_ctl = snd_hda_codec_read(codec, nid, 0,
1480 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
1481 new_ctl = ctls[ucontrol->value.enumerated.item[0]];
1482 if (old_ctl != new_ctl) {
1483 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, new_ctl);
1484 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
1485 ucontrol->value.enumerated.item[0] >= 3 ? 0xb080 : 0xb000);
1486 return 1;
1488 return 0;
1491 static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
1493 static char *texts[] = {
1494 "Front", "Surround", "CLFE", "Side"
1496 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1497 uinfo->count = 1;
1498 uinfo->value.enumerated.items = 4;
1499 if (uinfo->value.enumerated.item >= 4)
1500 uinfo->value.enumerated.item = 3;
1501 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1502 return 0;
1505 static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1507 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1508 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
1509 unsigned int sel;
1511 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
1512 ucontrol->value.enumerated.item[0] = sel & 3;
1513 return 0;
1516 static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1518 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1519 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
1520 unsigned int sel;
1522 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
1523 if (ucontrol->value.enumerated.item[0] != sel) {
1524 sel = ucontrol->value.enumerated.item[0] & 3;
1525 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, sel);
1526 return 1;
1528 return 0;
1531 #define PIN_CTL_TEST(xname,nid) { \
1532 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1533 .name = xname, \
1534 .info = alc_test_pin_ctl_info, \
1535 .get = alc_test_pin_ctl_get, \
1536 .put = alc_test_pin_ctl_put, \
1537 .private_value = nid \
1540 #define PIN_SRC_TEST(xname,nid) { \
1541 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1542 .name = xname, \
1543 .info = alc_test_pin_src_info, \
1544 .get = alc_test_pin_src_get, \
1545 .put = alc_test_pin_src_put, \
1546 .private_value = nid \
1549 static struct snd_kcontrol_new alc880_test_mixer[] = {
1550 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1551 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1552 HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
1553 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
1554 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
1555 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
1556 HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
1557 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
1558 PIN_CTL_TEST("Front Pin Mode", 0x14),
1559 PIN_CTL_TEST("Surround Pin Mode", 0x15),
1560 PIN_CTL_TEST("CLFE Pin Mode", 0x16),
1561 PIN_CTL_TEST("Side Pin Mode", 0x17),
1562 PIN_CTL_TEST("In-1 Pin Mode", 0x18),
1563 PIN_CTL_TEST("In-2 Pin Mode", 0x19),
1564 PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
1565 PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
1566 PIN_SRC_TEST("In-1 Pin Source", 0x18),
1567 PIN_SRC_TEST("In-2 Pin Source", 0x19),
1568 PIN_SRC_TEST("In-3 Pin Source", 0x1a),
1569 PIN_SRC_TEST("In-4 Pin Source", 0x1b),
1570 HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
1571 HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
1572 HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
1573 HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
1574 HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
1575 HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
1576 HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
1577 HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
1578 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
1579 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
1581 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1582 .name = "Channel Mode",
1583 .info = alc_ch_mode_info,
1584 .get = alc_ch_mode_get,
1585 .put = alc_ch_mode_put,
1587 { } /* end */
1590 static struct hda_verb alc880_test_init_verbs[] = {
1591 /* Unmute inputs of 0x0c - 0x0f */
1592 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1593 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1594 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1595 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1596 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1597 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1598 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1599 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1600 /* Vol output for 0x0c-0x0f */
1601 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1602 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1603 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1604 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1605 /* Set output pins 0x14-0x17 */
1606 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1607 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1608 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1609 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1610 /* Unmute output pins 0x14-0x17 */
1611 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1612 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1613 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1614 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1615 /* Set input pins 0x18-0x1c */
1616 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1617 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1618 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1619 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1620 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1621 /* Mute input pins 0x18-0x1b */
1622 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1623 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1624 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1625 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1626 /* ADC set up */
1627 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1628 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
1629 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1630 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
1631 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1632 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
1633 /* Analog input/passthru */
1634 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1635 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1636 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
1637 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
1638 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
1641 #endif
1646 static struct hda_board_config alc880_cfg_tbl[] = {
1647 /* Back 3 jack, front 2 jack */
1648 { .modelname = "3stack", .config = ALC880_3ST },
1649 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe200, .config = ALC880_3ST },
1650 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe201, .config = ALC880_3ST },
1651 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe202, .config = ALC880_3ST },
1652 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe203, .config = ALC880_3ST },
1653 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe204, .config = ALC880_3ST },
1654 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe205, .config = ALC880_3ST },
1655 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe206, .config = ALC880_3ST },
1656 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe207, .config = ALC880_3ST },
1657 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe208, .config = ALC880_3ST },
1658 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe209, .config = ALC880_3ST },
1659 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20a, .config = ALC880_3ST },
1660 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20b, .config = ALC880_3ST },
1661 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20c, .config = ALC880_3ST },
1662 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20d, .config = ALC880_3ST },
1663 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20e, .config = ALC880_3ST },
1664 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20f, .config = ALC880_3ST },
1665 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe210, .config = ALC880_3ST },
1666 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe211, .config = ALC880_3ST },
1667 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe214, .config = ALC880_3ST },
1668 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe302, .config = ALC880_3ST },
1669 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe303, .config = ALC880_3ST },
1670 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe304, .config = ALC880_3ST },
1671 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe306, .config = ALC880_3ST },
1672 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe307, .config = ALC880_3ST },
1673 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe404, .config = ALC880_3ST },
1674 { .pci_subvendor = 0x8086, .pci_subdevice = 0xa101, .config = ALC880_3ST },
1675 { .pci_subvendor = 0x107b, .pci_subdevice = 0x3031, .config = ALC880_3ST },
1676 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4036, .config = ALC880_3ST },
1677 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4037, .config = ALC880_3ST },
1678 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4038, .config = ALC880_3ST },
1679 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4040, .config = ALC880_3ST },
1680 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4041, .config = ALC880_3ST },
1681 /* TCL S700 */
1682 { .pci_subvendor = 0x19db, .pci_subdevice = 0x4188, .config = ALC880_TCL_S700 },
1684 /* Back 3 jack, front 2 jack (Internal add Aux-In) */
1685 { .pci_subvendor = 0x1025, .pci_subdevice = 0xe310, .config = ALC880_3ST },
1686 { .pci_subvendor = 0x104d, .pci_subdevice = 0x81d6, .config = ALC880_3ST },
1687 { .pci_subvendor = 0x104d, .pci_subdevice = 0x81a0, .config = ALC880_3ST },
1689 /* Back 3 jack plus 1 SPDIF out jack, front 2 jack */
1690 { .modelname = "3stack-digout", .config = ALC880_3ST_DIG },
1691 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe308, .config = ALC880_3ST_DIG },
1692 { .pci_subvendor = 0x1025, .pci_subdevice = 0x0070, .config = ALC880_3ST_DIG },
1693 /* Clevo m520G NB */
1694 { .pci_subvendor = 0x1558, .pci_subdevice = 0x0520, .config = ALC880_CLEVO },
1696 /* Back 3 jack plus 1 SPDIF out jack, front 2 jack (Internal add Aux-In)*/
1697 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe305, .config = ALC880_3ST_DIG },
1698 { .pci_subvendor = 0x8086, .pci_subdevice = 0xd402, .config = ALC880_3ST_DIG },
1699 { .pci_subvendor = 0x1025, .pci_subdevice = 0xe309, .config = ALC880_3ST_DIG },
1701 /* Back 5 jack, front 2 jack */
1702 { .modelname = "5stack", .config = ALC880_5ST },
1703 { .pci_subvendor = 0x107b, .pci_subdevice = 0x3033, .config = ALC880_5ST },
1704 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4039, .config = ALC880_5ST },
1705 { .pci_subvendor = 0x107b, .pci_subdevice = 0x3032, .config = ALC880_5ST },
1706 { .pci_subvendor = 0x103c, .pci_subdevice = 0x2a09, .config = ALC880_5ST },
1707 { .pci_subvendor = 0x1043, .pci_subdevice = 0x814e, .config = ALC880_5ST },
1709 /* Back 5 jack plus 1 SPDIF out jack, front 2 jack */
1710 { .modelname = "5stack-digout", .config = ALC880_5ST_DIG },
1711 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe224, .config = ALC880_5ST_DIG },
1712 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe400, .config = ALC880_5ST_DIG },
1713 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe401, .config = ALC880_5ST_DIG },
1714 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe402, .config = ALC880_5ST_DIG },
1715 { .pci_subvendor = 0x8086, .pci_subdevice = 0xd400, .config = ALC880_5ST_DIG },
1716 { .pci_subvendor = 0x8086, .pci_subdevice = 0xd401, .config = ALC880_5ST_DIG },
1717 { .pci_subvendor = 0x8086, .pci_subdevice = 0xa100, .config = ALC880_5ST_DIG },
1718 { .pci_subvendor = 0x1565, .pci_subdevice = 0x8202, .config = ALC880_5ST_DIG },
1719 { .pci_subvendor = 0x1019, .pci_subdevice = 0xa880, .config = ALC880_5ST_DIG },
1720 /* { .pci_subvendor = 0x1019, .pci_subdevice = 0xa884, .config = ALC880_5ST_DIG }, */ /* conflict with 6stack */
1721 { .pci_subvendor = 0x1695, .pci_subdevice = 0x400d, .config = ALC880_5ST_DIG },
1722 /* note subvendor = 0 below */
1723 /* { .pci_subvendor = 0x0000, .pci_subdevice = 0x8086, .config = ALC880_5ST_DIG }, */
1725 { .modelname = "w810", .config = ALC880_W810 },
1726 { .pci_subvendor = 0x161f, .pci_subdevice = 0x203d, .config = ALC880_W810 },
1728 { .modelname = "z71v", .config = ALC880_Z71V },
1729 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_Z71V },
1731 { .modelname = "6stack", .config = ALC880_6ST },
1732 { .pci_subvendor = 0x1043, .pci_subdevice = 0x8196, .config = ALC880_6ST }, /* ASUS P5GD1-HVM */
1733 { .pci_subvendor = 0x1043, .pci_subdevice = 0x81b4, .config = ALC880_6ST },
1734 { .pci_subvendor = 0x1019, .pci_subdevice = 0xa884, .config = ALC880_6ST }, /* Acer APFV */
1735 { .pci_subvendor = 0x1458, .pci_subdevice = 0xa102, .config = ALC880_6ST }, /* Gigabyte K8N51 */
1737 { .modelname = "6stack-digout", .config = ALC880_6ST_DIG },
1738 { .pci_subvendor = 0x2668, .pci_subdevice = 0x8086, .config = ALC880_6ST_DIG },
1739 { .pci_subvendor = 0x8086, .pci_subdevice = 0x2668, .config = ALC880_6ST_DIG },
1740 { .pci_subvendor = 0x1462, .pci_subdevice = 0x1150, .config = ALC880_6ST_DIG },
1741 { .pci_subvendor = 0xe803, .pci_subdevice = 0x1019, .config = ALC880_6ST_DIG },
1742 { .pci_subvendor = 0x1039, .pci_subdevice = 0x1234, .config = ALC880_6ST_DIG },
1743 { .pci_subvendor = 0x1025, .pci_subdevice = 0x0077, .config = ALC880_6ST_DIG },
1744 { .pci_subvendor = 0x1025, .pci_subdevice = 0x0078, .config = ALC880_6ST_DIG },
1745 { .pci_subvendor = 0x1025, .pci_subdevice = 0x0087, .config = ALC880_6ST_DIG },
1746 { .pci_subvendor = 0x1297, .pci_subdevice = 0xc790, .config = ALC880_6ST_DIG }, /* Shuttle ST20G5 */
1748 { .modelname = "asus", .config = ALC880_ASUS },
1749 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_ASUS_DIG },
1750 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1973, .config = ALC880_ASUS_DIG },
1751 { .pci_subvendor = 0x1043, .pci_subdevice = 0x19b3, .config = ALC880_ASUS_DIG },
1752 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1113, .config = ALC880_ASUS_DIG },
1753 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1173, .config = ALC880_ASUS_DIG },
1754 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1993, .config = ALC880_ASUS },
1755 { .pci_subvendor = 0x1043, .pci_subdevice = 0x10c3, .config = ALC880_ASUS_DIG },
1756 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1133, .config = ALC880_ASUS },
1757 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1123, .config = ALC880_ASUS_DIG },
1758 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1143, .config = ALC880_ASUS },
1759 { .pci_subvendor = 0x1043, .pci_subdevice = 0x10b3, .config = ALC880_ASUS_W1V },
1760 { .pci_subvendor = 0x1558, .pci_subdevice = 0x5401, .config = ALC880_ASUS_DIG2 },
1762 { .modelname = "uniwill", .config = ALC880_UNIWILL_DIG },
1763 { .pci_subvendor = 0x1584, .pci_subdevice = 0x9050, .config = ALC880_UNIWILL_DIG },
1765 { .modelname = "F1734", .config = ALC880_F1734 },
1766 { .pci_subvendor = 0x1734, .pci_subdevice = 0x107c, .config = ALC880_F1734 },
1767 { .pci_subvendor = 0x1584, .pci_subdevice = 0x9054, .config = ALC880_F1734 },
1769 #ifdef CONFIG_SND_DEBUG
1770 { .modelname = "test", .config = ALC880_TEST },
1771 #endif
1772 { .modelname = "auto", .config = ALC880_AUTO },
1778 * ALC880 codec presets
1780 static struct alc_config_preset alc880_presets[] = {
1781 [ALC880_3ST] = {
1782 .mixers = { alc880_three_stack_mixer },
1783 .init_verbs = { alc880_volume_init_verbs, alc880_pin_3stack_init_verbs },
1784 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
1785 .dac_nids = alc880_dac_nids,
1786 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
1787 .channel_mode = alc880_threestack_modes,
1788 .input_mux = &alc880_capture_source,
1790 [ALC880_3ST_DIG] = {
1791 .mixers = { alc880_three_stack_mixer },
1792 .init_verbs = { alc880_volume_init_verbs, alc880_pin_3stack_init_verbs },
1793 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
1794 .dac_nids = alc880_dac_nids,
1795 .dig_out_nid = ALC880_DIGOUT_NID,
1796 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
1797 .channel_mode = alc880_threestack_modes,
1798 .input_mux = &alc880_capture_source,
1800 [ALC880_TCL_S700] = {
1801 .mixers = { alc880_tcl_s700_mixer },
1802 .init_verbs = { alc880_volume_init_verbs,
1803 alc880_pin_tcl_S700_init_verbs,
1804 alc880_gpio2_init_verbs },
1805 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
1806 .dac_nids = alc880_dac_nids,
1807 .hp_nid = 0x03,
1808 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
1809 .channel_mode = alc880_2_jack_modes,
1810 .input_mux = &alc880_capture_source,
1812 [ALC880_5ST] = {
1813 .mixers = { alc880_three_stack_mixer, alc880_five_stack_mixer},
1814 .init_verbs = { alc880_volume_init_verbs, alc880_pin_5stack_init_verbs },
1815 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
1816 .dac_nids = alc880_dac_nids,
1817 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
1818 .channel_mode = alc880_fivestack_modes,
1819 .input_mux = &alc880_capture_source,
1821 [ALC880_5ST_DIG] = {
1822 .mixers = { alc880_three_stack_mixer, alc880_five_stack_mixer },
1823 .init_verbs = { alc880_volume_init_verbs, alc880_pin_5stack_init_verbs },
1824 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
1825 .dac_nids = alc880_dac_nids,
1826 .dig_out_nid = ALC880_DIGOUT_NID,
1827 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
1828 .channel_mode = alc880_fivestack_modes,
1829 .input_mux = &alc880_capture_source,
1831 [ALC880_6ST] = {
1832 .mixers = { alc880_six_stack_mixer },
1833 .init_verbs = { alc880_volume_init_verbs, alc880_pin_6stack_init_verbs },
1834 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
1835 .dac_nids = alc880_6st_dac_nids,
1836 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
1837 .channel_mode = alc880_sixstack_modes,
1838 .input_mux = &alc880_6stack_capture_source,
1840 [ALC880_6ST_DIG] = {
1841 .mixers = { alc880_six_stack_mixer },
1842 .init_verbs = { alc880_volume_init_verbs, alc880_pin_6stack_init_verbs },
1843 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
1844 .dac_nids = alc880_6st_dac_nids,
1845 .dig_out_nid = ALC880_DIGOUT_NID,
1846 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
1847 .channel_mode = alc880_sixstack_modes,
1848 .input_mux = &alc880_6stack_capture_source,
1850 [ALC880_W810] = {
1851 .mixers = { alc880_w810_base_mixer },
1852 .init_verbs = { alc880_volume_init_verbs, alc880_pin_w810_init_verbs,
1853 alc880_gpio2_init_verbs },
1854 .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
1855 .dac_nids = alc880_w810_dac_nids,
1856 .dig_out_nid = ALC880_DIGOUT_NID,
1857 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
1858 .channel_mode = alc880_w810_modes,
1859 .input_mux = &alc880_capture_source,
1861 [ALC880_Z71V] = {
1862 .mixers = { alc880_z71v_mixer },
1863 .init_verbs = { alc880_volume_init_verbs, alc880_pin_z71v_init_verbs },
1864 .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
1865 .dac_nids = alc880_z71v_dac_nids,
1866 .dig_out_nid = ALC880_DIGOUT_NID,
1867 .hp_nid = 0x03,
1868 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
1869 .channel_mode = alc880_2_jack_modes,
1870 .input_mux = &alc880_capture_source,
1872 [ALC880_F1734] = {
1873 .mixers = { alc880_f1734_mixer },
1874 .init_verbs = { alc880_volume_init_verbs, alc880_pin_f1734_init_verbs },
1875 .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
1876 .dac_nids = alc880_f1734_dac_nids,
1877 .hp_nid = 0x02,
1878 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
1879 .channel_mode = alc880_2_jack_modes,
1880 .input_mux = &alc880_capture_source,
1882 [ALC880_ASUS] = {
1883 .mixers = { alc880_asus_mixer },
1884 .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs,
1885 alc880_gpio1_init_verbs },
1886 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
1887 .dac_nids = alc880_asus_dac_nids,
1888 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
1889 .channel_mode = alc880_asus_modes,
1890 .input_mux = &alc880_capture_source,
1892 [ALC880_ASUS_DIG] = {
1893 .mixers = { alc880_asus_mixer },
1894 .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs,
1895 alc880_gpio1_init_verbs },
1896 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
1897 .dac_nids = alc880_asus_dac_nids,
1898 .dig_out_nid = ALC880_DIGOUT_NID,
1899 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
1900 .channel_mode = alc880_asus_modes,
1901 .input_mux = &alc880_capture_source,
1903 [ALC880_ASUS_DIG2] = {
1904 .mixers = { alc880_asus_mixer },
1905 .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs,
1906 alc880_gpio2_init_verbs }, /* use GPIO2 */
1907 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
1908 .dac_nids = alc880_asus_dac_nids,
1909 .dig_out_nid = ALC880_DIGOUT_NID,
1910 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
1911 .channel_mode = alc880_asus_modes,
1912 .input_mux = &alc880_capture_source,
1914 [ALC880_ASUS_W1V] = {
1915 .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer },
1916 .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs,
1917 alc880_gpio1_init_verbs },
1918 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
1919 .dac_nids = alc880_asus_dac_nids,
1920 .dig_out_nid = ALC880_DIGOUT_NID,
1921 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
1922 .channel_mode = alc880_asus_modes,
1923 .input_mux = &alc880_capture_source,
1925 [ALC880_UNIWILL_DIG] = {
1926 .mixers = { alc880_asus_mixer, alc880_pcbeep_mixer },
1927 .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs },
1928 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
1929 .dac_nids = alc880_asus_dac_nids,
1930 .dig_out_nid = ALC880_DIGOUT_NID,
1931 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
1932 .channel_mode = alc880_asus_modes,
1933 .input_mux = &alc880_capture_source,
1935 [ALC880_CLEVO] = {
1936 .mixers = { alc880_three_stack_mixer },
1937 .init_verbs = { alc880_volume_init_verbs,
1938 alc880_pin_clevo_init_verbs },
1939 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
1940 .dac_nids = alc880_dac_nids,
1941 .hp_nid = 0x03,
1942 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
1943 .channel_mode = alc880_threestack_modes,
1944 .input_mux = &alc880_capture_source,
1946 #ifdef CONFIG_SND_DEBUG
1947 [ALC880_TEST] = {
1948 .mixers = { alc880_test_mixer },
1949 .init_verbs = { alc880_test_init_verbs },
1950 .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
1951 .dac_nids = alc880_test_dac_nids,
1952 .dig_out_nid = ALC880_DIGOUT_NID,
1953 .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
1954 .channel_mode = alc880_test_modes,
1955 .input_mux = &alc880_test_capture_source,
1957 #endif
1961 * Automatic parse of I/O pins from the BIOS configuration
1964 #define NUM_CONTROL_ALLOC 32
1965 #define NUM_VERB_ALLOC 32
1967 enum {
1968 ALC_CTL_WIDGET_VOL,
1969 ALC_CTL_WIDGET_MUTE,
1970 ALC_CTL_BIND_MUTE,
1972 static struct snd_kcontrol_new alc880_control_templates[] = {
1973 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
1974 HDA_CODEC_MUTE(NULL, 0, 0, 0),
1975 HDA_BIND_MUTE(NULL, 0, 0, 0),
1978 /* add dynamic controls */
1979 static int add_control(struct alc_spec *spec, int type, const char *name, unsigned long val)
1981 struct snd_kcontrol_new *knew;
1983 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
1984 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
1986 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */
1987 if (! knew)
1988 return -ENOMEM;
1989 if (spec->kctl_alloc) {
1990 memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc);
1991 kfree(spec->kctl_alloc);
1993 spec->kctl_alloc = knew;
1994 spec->num_kctl_alloc = num;
1997 knew = &spec->kctl_alloc[spec->num_kctl_used];
1998 *knew = alc880_control_templates[type];
1999 knew->name = kstrdup(name, GFP_KERNEL);
2000 if (! knew->name)
2001 return -ENOMEM;
2002 knew->private_value = val;
2003 spec->num_kctl_used++;
2004 return 0;
2007 #define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
2008 #define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
2009 #define alc880_is_multi_pin(nid) ((nid) >= 0x18)
2010 #define alc880_multi_pin_idx(nid) ((nid) - 0x18)
2011 #define alc880_is_input_pin(nid) ((nid) >= 0x18)
2012 #define alc880_input_pin_idx(nid) ((nid) - 0x18)
2013 #define alc880_idx_to_dac(nid) ((nid) + 0x02)
2014 #define alc880_dac_to_idx(nid) ((nid) - 0x02)
2015 #define alc880_idx_to_mixer(nid) ((nid) + 0x0c)
2016 #define alc880_idx_to_selector(nid) ((nid) + 0x10)
2017 #define ALC880_PIN_CD_NID 0x1c
2019 /* fill in the dac_nids table from the parsed pin configuration */
2020 static int alc880_auto_fill_dac_nids(struct alc_spec *spec, const struct auto_pin_cfg *cfg)
2022 hda_nid_t nid;
2023 int assigned[4];
2024 int i, j;
2026 memset(assigned, 0, sizeof(assigned));
2027 spec->multiout.dac_nids = spec->private_dac_nids;
2029 /* check the pins hardwired to audio widget */
2030 for (i = 0; i < cfg->line_outs; i++) {
2031 nid = cfg->line_out_pins[i];
2032 if (alc880_is_fixed_pin(nid)) {
2033 int idx = alc880_fixed_pin_idx(nid);
2034 spec->multiout.dac_nids[i] = alc880_idx_to_dac(idx);
2035 assigned[idx] = 1;
2038 /* left pins can be connect to any audio widget */
2039 for (i = 0; i < cfg->line_outs; i++) {
2040 nid = cfg->line_out_pins[i];
2041 if (alc880_is_fixed_pin(nid))
2042 continue;
2043 /* search for an empty channel */
2044 for (j = 0; j < cfg->line_outs; j++) {
2045 if (! assigned[j]) {
2046 spec->multiout.dac_nids[i] = alc880_idx_to_dac(j);
2047 assigned[j] = 1;
2048 break;
2052 spec->multiout.num_dacs = cfg->line_outs;
2053 return 0;
2056 /* add playback controls from the parsed DAC table */
2057 static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
2058 const struct auto_pin_cfg *cfg)
2060 char name[32];
2061 static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" };
2062 hda_nid_t nid;
2063 int i, err;
2065 for (i = 0; i < cfg->line_outs; i++) {
2066 if (! spec->multiout.dac_nids[i])
2067 continue;
2068 nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
2069 if (i == 2) {
2070 /* Center/LFE */
2071 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Center Playback Volume",
2072 HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT))) < 0)
2073 return err;
2074 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "LFE Playback Volume",
2075 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0)
2076 return err;
2077 if ((err = add_control(spec, ALC_CTL_BIND_MUTE, "Center Playback Switch",
2078 HDA_COMPOSE_AMP_VAL(nid, 1, 2, HDA_INPUT))) < 0)
2079 return err;
2080 if ((err = add_control(spec, ALC_CTL_BIND_MUTE, "LFE Playback Switch",
2081 HDA_COMPOSE_AMP_VAL(nid, 2, 2, HDA_INPUT))) < 0)
2082 return err;
2083 } else {
2084 sprintf(name, "%s Playback Volume", chname[i]);
2085 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
2086 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
2087 return err;
2088 sprintf(name, "%s Playback Switch", chname[i]);
2089 if ((err = add_control(spec, ALC_CTL_BIND_MUTE, name,
2090 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT))) < 0)
2091 return err;
2094 return 0;
2097 /* add playback controls for speaker and HP outputs */
2098 static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
2099 const char *pfx)
2101 hda_nid_t nid;
2102 int err;
2103 char name[32];
2105 if (! pin)
2106 return 0;
2108 if (alc880_is_fixed_pin(pin)) {
2109 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
2110 if (! spec->multiout.dac_nids[0]) {
2111 /* use this as the primary output */
2112 spec->multiout.dac_nids[0] = nid;
2113 if (! spec->multiout.num_dacs)
2114 spec->multiout.num_dacs = 1;
2115 } else
2116 /* specify the DAC as the extra output */
2117 spec->multiout.hp_nid = nid;
2118 /* control HP volume/switch on the output mixer amp */
2119 nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
2120 sprintf(name, "%s Playback Volume", pfx);
2121 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
2122 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
2123 return err;
2124 sprintf(name, "%s Playback Switch", pfx);
2125 if ((err = add_control(spec, ALC_CTL_BIND_MUTE, name,
2126 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT))) < 0)
2127 return err;
2128 } else if (alc880_is_multi_pin(pin)) {
2129 /* set manual connection */
2130 if (! spec->multiout.dac_nids[0]) {
2131 /* use this as the primary output */
2132 spec->multiout.dac_nids[0] = alc880_idx_to_dac(alc880_multi_pin_idx(pin));
2133 if (! spec->multiout.num_dacs)
2134 spec->multiout.num_dacs = 1;
2136 /* we have only a switch on HP-out PIN */
2137 sprintf(name, "%s Playback Switch", pfx);
2138 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
2139 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT))) < 0)
2140 return err;
2142 return 0;
2145 /* create input playback/capture controls for the given pin */
2146 static int new_analog_input(struct alc_spec *spec, hda_nid_t pin, const char *ctlname,
2147 int idx, hda_nid_t mix_nid)
2149 char name[32];
2150 int err;
2152 sprintf(name, "%s Playback Volume", ctlname);
2153 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
2154 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT))) < 0)
2155 return err;
2156 sprintf(name, "%s Playback Switch", ctlname);
2157 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
2158 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT))) < 0)
2159 return err;
2160 return 0;
2163 /* create playback/capture controls for input pins */
2164 static int alc880_auto_create_analog_input_ctls(struct alc_spec *spec,
2165 const struct auto_pin_cfg *cfg)
2167 struct hda_input_mux *imux = &spec->private_imux;
2168 int i, err, idx;
2170 for (i = 0; i < AUTO_PIN_LAST; i++) {
2171 if (alc880_is_input_pin(cfg->input_pins[i])) {
2172 idx = alc880_input_pin_idx(cfg->input_pins[i]);
2173 err = new_analog_input(spec, cfg->input_pins[i],
2174 auto_pin_cfg_labels[i],
2175 idx, 0x0b);
2176 if (err < 0)
2177 return err;
2178 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
2179 imux->items[imux->num_items].index = alc880_input_pin_idx(cfg->input_pins[i]);
2180 imux->num_items++;
2183 return 0;
2186 static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
2187 hda_nid_t nid, int pin_type,
2188 int dac_idx)
2190 /* set as output */
2191 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
2192 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
2193 /* need the manual connection? */
2194 if (alc880_is_multi_pin(nid)) {
2195 struct alc_spec *spec = codec->spec;
2196 int idx = alc880_multi_pin_idx(nid);
2197 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
2198 AC_VERB_SET_CONNECT_SEL,
2199 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
2203 static void alc880_auto_init_multi_out(struct hda_codec *codec)
2205 struct alc_spec *spec = codec->spec;
2206 int i;
2208 for (i = 0; i < spec->autocfg.line_outs; i++) {
2209 hda_nid_t nid = spec->autocfg.line_out_pins[i];
2210 alc880_auto_set_output_and_unmute(codec, nid, PIN_OUT, i);
2214 static void alc880_auto_init_extra_out(struct hda_codec *codec)
2216 struct alc_spec *spec = codec->spec;
2217 hda_nid_t pin;
2219 pin = spec->autocfg.speaker_pin;
2220 if (pin) /* connect to front */
2221 alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
2222 pin = spec->autocfg.hp_pin;
2223 if (pin) /* connect to front */
2224 alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
2227 static void alc880_auto_init_analog_input(struct hda_codec *codec)
2229 struct alc_spec *spec = codec->spec;
2230 int i;
2232 for (i = 0; i < AUTO_PIN_LAST; i++) {
2233 hda_nid_t nid = spec->autocfg.input_pins[i];
2234 if (alc880_is_input_pin(nid)) {
2235 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
2236 i <= AUTO_PIN_FRONT_MIC ? PIN_VREF80 : PIN_IN);
2237 if (nid != ALC880_PIN_CD_NID)
2238 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
2239 AMP_OUT_MUTE);
2244 /* parse the BIOS configuration and set up the alc_spec */
2245 /* return 1 if successful, 0 if the proper config is not found, or a negative error code */
2246 static int alc880_parse_auto_config(struct hda_codec *codec)
2248 struct alc_spec *spec = codec->spec;
2249 int err;
2250 static hda_nid_t alc880_ignore[] = { 0x1d, 0 };
2252 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
2253 alc880_ignore)) < 0)
2254 return err;
2255 if (! spec->autocfg.line_outs && ! spec->autocfg.speaker_pin &&
2256 ! spec->autocfg.hp_pin)
2257 return 0; /* can't find valid BIOS pin config */
2259 if ((err = alc880_auto_fill_dac_nids(spec, &spec->autocfg)) < 0 ||
2260 (err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 ||
2261 (err = alc880_auto_create_extra_out(spec, spec->autocfg.speaker_pin,
2262 "Speaker")) < 0 ||
2263 (err = alc880_auto_create_extra_out(spec, spec->autocfg.speaker_pin,
2264 "Headphone")) < 0 ||
2265 (err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
2266 return err;
2268 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
2270 if (spec->autocfg.dig_out_pin)
2271 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
2272 if (spec->autocfg.dig_in_pin)
2273 spec->dig_in_nid = ALC880_DIGIN_NID;
2275 if (spec->kctl_alloc)
2276 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2278 spec->init_verbs[spec->num_init_verbs++] = alc880_volume_init_verbs;
2280 spec->input_mux = &spec->private_imux;
2282 return 1;
2285 /* init callback for auto-configuration model -- overriding the default init */
2286 static int alc880_auto_init(struct hda_codec *codec)
2288 alc_init(codec);
2289 alc880_auto_init_multi_out(codec);
2290 alc880_auto_init_extra_out(codec);
2291 alc880_auto_init_analog_input(codec);
2292 return 0;
2296 * OK, here we have finally the patch for ALC880
2299 static int patch_alc880(struct hda_codec *codec)
2301 struct alc_spec *spec;
2302 int board_config;
2303 int err;
2305 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
2306 if (spec == NULL)
2307 return -ENOMEM;
2309 codec->spec = spec;
2311 board_config = snd_hda_check_board_config(codec, alc880_cfg_tbl);
2312 if (board_config < 0 || board_config >= ALC880_MODEL_LAST) {
2313 printk(KERN_INFO "hda_codec: Unknown model for ALC880, trying auto-probe from BIOS...\n");
2314 board_config = ALC880_AUTO;
2317 if (board_config == ALC880_AUTO) {
2318 /* automatic parse from the BIOS config */
2319 err = alc880_parse_auto_config(codec);
2320 if (err < 0) {
2321 alc_free(codec);
2322 return err;
2323 } else if (! err) {
2324 printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using 3-stack mode...\n");
2325 board_config = ALC880_3ST;
2329 if (board_config != ALC880_AUTO)
2330 setup_preset(spec, &alc880_presets[board_config]);
2332 spec->stream_name_analog = "ALC880 Analog";
2333 spec->stream_analog_playback = &alc880_pcm_analog_playback;
2334 spec->stream_analog_capture = &alc880_pcm_analog_capture;
2336 spec->stream_name_digital = "ALC880 Digital";
2337 spec->stream_digital_playback = &alc880_pcm_digital_playback;
2338 spec->stream_digital_capture = &alc880_pcm_digital_capture;
2340 if (! spec->adc_nids && spec->input_mux) {
2341 /* check whether NID 0x07 is valid */
2342 unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
2343 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */
2344 if (wcap != AC_WID_AUD_IN) {
2345 spec->adc_nids = alc880_adc_nids_alt;
2346 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
2347 spec->mixers[spec->num_mixers] = alc880_capture_alt_mixer;
2348 spec->num_mixers++;
2349 } else {
2350 spec->adc_nids = alc880_adc_nids;
2351 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
2352 spec->mixers[spec->num_mixers] = alc880_capture_mixer;
2353 spec->num_mixers++;
2357 codec->patch_ops = alc_patch_ops;
2358 if (board_config == ALC880_AUTO)
2359 codec->patch_ops.init = alc880_auto_init;
2361 return 0;
2366 * ALC260 support
2369 static hda_nid_t alc260_dac_nids[1] = {
2370 /* front */
2371 0x02,
2374 static hda_nid_t alc260_adc_nids[1] = {
2375 /* ADC0 */
2376 0x04,
2379 static hda_nid_t alc260_adc_nids_alt[1] = {
2380 /* ADC1 */
2381 0x05,
2384 static hda_nid_t alc260_hp_adc_nids[2] = {
2385 /* ADC1, 0 */
2386 0x05, 0x04
2389 static hda_nid_t alc260_fujitsu_adc_nids[2] = {
2390 /* ADC0, ADC1 */
2391 0x04, 0x05
2394 #define ALC260_DIGOUT_NID 0x03
2395 #define ALC260_DIGIN_NID 0x06
2397 static struct hda_input_mux alc260_capture_source = {
2398 .num_items = 4,
2399 .items = {
2400 { "Mic", 0x0 },
2401 { "Front Mic", 0x1 },
2402 { "Line", 0x2 },
2403 { "CD", 0x4 },
2407 /* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack
2408 * and the internal CD lines.
2410 static struct hda_input_mux alc260_fujitsu_capture_source = {
2411 .num_items = 3,
2412 .items = {
2413 { "Mic/Line", 0x0 },
2414 { "CD", 0x4 },
2415 { "Headphone", 0x2 },
2420 * This is just place-holder, so there's something for alc_build_pcms to look
2421 * at when it calculates the maximum number of channels. ALC260 has no mixer
2422 * element which allows changing the channel mode, so the verb list is
2423 * never used.
2425 static struct hda_channel_mode alc260_modes[1] = {
2426 { 2, NULL },
2430 /* Mixer combinations
2432 * basic: base_output + input + pc_beep + capture
2433 * HP: base_output + input + capture_alt
2434 * HP_3013: hp_3013 + input + capture
2435 * fujitsu: fujitsu + capture
2438 static struct snd_kcontrol_new alc260_base_output_mixer[] = {
2439 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
2440 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
2441 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
2442 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
2443 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
2444 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
2445 { } /* end */
2448 static struct snd_kcontrol_new alc260_input_mixer[] = {
2449 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
2450 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
2451 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
2452 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
2453 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
2454 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
2455 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
2456 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
2457 { } /* end */
2460 static struct snd_kcontrol_new alc260_pc_beep_mixer[] = {
2461 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x07, 0x05, HDA_INPUT),
2462 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x07, 0x05, HDA_INPUT),
2463 { } /* end */
2466 static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
2467 HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
2468 HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
2469 HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
2470 HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
2471 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
2472 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
2473 HDA_CODEC_VOLUME_MONO("iSpeaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
2474 HDA_CODEC_MUTE_MONO("iSpeaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
2475 { } /* end */
2478 static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
2479 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
2480 HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
2481 ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
2482 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
2483 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
2484 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
2485 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
2486 ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
2487 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
2488 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
2489 HDA_CODEC_VOLUME("Internal Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
2490 HDA_BIND_MUTE("Internal Speaker Playback Switch", 0x09, 2, HDA_INPUT),
2491 { } /* end */
2494 /* capture mixer elements */
2495 static struct snd_kcontrol_new alc260_capture_mixer[] = {
2496 HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT),
2497 HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT),
2498 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x05, 0x0, HDA_INPUT),
2499 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x05, 0x0, HDA_INPUT),
2501 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2502 /* The multiple "Capture Source" controls confuse alsamixer
2503 * So call somewhat different..
2504 * FIXME: the controls appear in the "playback" view!
2506 /* .name = "Capture Source", */
2507 .name = "Input Source",
2508 .count = 2,
2509 .info = alc_mux_enum_info,
2510 .get = alc_mux_enum_get,
2511 .put = alc_mux_enum_put,
2513 { } /* end */
2516 static struct snd_kcontrol_new alc260_capture_alt_mixer[] = {
2517 HDA_CODEC_VOLUME("Capture Volume", 0x05, 0x0, HDA_INPUT),
2518 HDA_CODEC_MUTE("Capture Switch", 0x05, 0x0, HDA_INPUT),
2520 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2521 /* The multiple "Capture Source" controls confuse alsamixer
2522 * So call somewhat different..
2523 * FIXME: the controls appear in the "playback" view!
2525 /* .name = "Capture Source", */
2526 .name = "Input Source",
2527 .count = 1,
2528 .info = alc_mux_enum_info,
2529 .get = alc_mux_enum_get,
2530 .put = alc_mux_enum_put,
2532 { } /* end */
2536 * initialization verbs
2538 static struct hda_verb alc260_init_verbs[] = {
2539 /* Line In pin widget for input */
2540 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2541 /* CD pin widget for input */
2542 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2543 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2544 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2545 /* Mic2 (front panel) pin widget for input and vref at 80% */
2546 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2547 /* LINE-2 is used for line-out in rear */
2548 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2549 /* select line-out */
2550 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
2551 /* LINE-OUT pin */
2552 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2553 /* enable HP */
2554 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2555 /* enable Mono */
2556 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2557 /* mute capture amp left and right */
2558 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2559 /* set connection select to line in (default select for this ADC) */
2560 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
2561 /* mute capture amp left and right */
2562 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2563 /* set connection select to line in (default select for this ADC) */
2564 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
2565 /* set vol=0 Line-Out mixer amp left and right */
2566 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2567 /* unmute pin widget amp left and right (no gain on this amp) */
2568 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2569 /* set vol=0 HP mixer amp left and right */
2570 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2571 /* unmute pin widget amp left and right (no gain on this amp) */
2572 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2573 /* set vol=0 Mono mixer amp left and right */
2574 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2575 /* unmute pin widget amp left and right (no gain on this amp) */
2576 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2577 /* unmute LINE-2 out pin */
2578 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2579 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */
2580 /* mute CD */
2581 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
2582 /* mute Line In */
2583 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
2584 /* mute Mic */
2585 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2586 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
2587 /* mute Front out path */
2588 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2589 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2590 /* mute Headphone out path */
2591 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2592 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2593 /* mute Mono out path */
2594 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2595 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2599 static struct hda_verb alc260_hp_init_verbs[] = {
2600 /* Headphone and output */
2601 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
2602 /* mono output */
2603 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2604 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2605 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
2606 /* Mic2 (front panel) pin widget for input and vref at 80% */
2607 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
2608 /* Line In pin widget for input */
2609 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
2610 /* Line-2 pin widget for output */
2611 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2612 /* CD pin widget for input */
2613 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
2614 /* unmute amp left and right */
2615 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
2616 /* set connection select to line in (default select for this ADC) */
2617 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
2618 /* unmute Line-Out mixer amp left and right (volume = 0) */
2619 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
2620 /* mute pin widget amp left and right (no gain on this amp) */
2621 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
2622 /* unmute HP mixer amp left and right (volume = 0) */
2623 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
2624 /* mute pin widget amp left and right (no gain on this amp) */
2625 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
2626 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */
2627 /* unmute CD */
2628 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
2629 /* unmute Line In */
2630 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
2631 /* unmute Mic */
2632 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2633 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
2634 /* Unmute Front out path */
2635 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2636 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2637 /* Unmute Headphone out path */
2638 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2639 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2640 /* Unmute Mono out path */
2641 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2642 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2646 static struct hda_verb alc260_hp_3013_init_verbs[] = {
2647 /* Line out and output */
2648 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2649 /* mono output */
2650 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2651 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2652 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
2653 /* Mic2 (front panel) pin widget for input and vref at 80% */
2654 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
2655 /* Line In pin widget for input */
2656 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
2657 /* Headphone pin widget for output */
2658 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
2659 /* CD pin widget for input */
2660 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
2661 /* unmute amp left and right */
2662 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
2663 /* set connection select to line in (default select for this ADC) */
2664 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
2665 /* unmute Line-Out mixer amp left and right (volume = 0) */
2666 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
2667 /* mute pin widget amp left and right (no gain on this amp) */
2668 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
2669 /* unmute HP mixer amp left and right (volume = 0) */
2670 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
2671 /* mute pin widget amp left and right (no gain on this amp) */
2672 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
2673 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */
2674 /* unmute CD */
2675 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
2676 /* unmute Line In */
2677 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
2678 /* unmute Mic */
2679 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2680 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
2681 /* Unmute Front out path */
2682 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2683 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2684 /* Unmute Headphone out path */
2685 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2686 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2687 /* Unmute Mono out path */
2688 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2689 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2693 /* Initialisation sequence for ALC260 as configured in Fujitsu S702x
2694 * laptops.
2696 static struct hda_verb alc260_fujitsu_init_verbs[] = {
2697 /* Disable all GPIOs */
2698 {0x01, AC_VERB_SET_GPIO_MASK, 0},
2699 /* Internal speaker is connected to headphone pin */
2700 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2701 /* Headphone/Line-out jack connects to Line1 pin; make it an output */
2702 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2703 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
2704 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2705 /* Ensure all other unused pins are disabled and muted.
2706 * Note: trying to set widget 0x15 to anything blocks all audio
2707 * output for some reason, so just leave that at the default.
2709 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2710 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2711 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2712 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2713 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2714 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2715 /* Disable digital (SPDIF) pins */
2716 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
2717 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
2719 /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
2720 * when acting as an output.
2722 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
2724 /* Start with mixer outputs muted */
2725 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2726 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2727 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2729 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
2730 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2731 /* Unmute Line1 pin widget amp left and right (no equiv mixer ctrl) */
2732 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2733 /* Unmute Line1 pin widget input for when this pin is used as input
2734 * (no equiv mixer ctrl). Having input and output unmuted doesn't
2735 * seem to cause a problem.
2737 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2738 /* Unmute pin widget used for Line-in (no equiv mixer ctrl) */
2739 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2741 /* Mute capture amp left and right */
2742 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2743 /* Set ADC connection select to match default mixer setting - line
2744 * in (on mic1 pin)
2746 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
2748 /* Do the same for the second ADC: mute capture input amp and
2749 * set ADC connection to line in
2751 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2752 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
2754 /* Mute all inputs to mixer widget (even unconnected ones) */
2755 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
2756 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
2757 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
2758 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
2759 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
2760 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
2761 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
2762 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
2767 static struct hda_pcm_stream alc260_pcm_analog_playback = {
2768 .substreams = 1,
2769 .channels_min = 2,
2770 .channels_max = 2,
2773 static struct hda_pcm_stream alc260_pcm_analog_capture = {
2774 .substreams = 1,
2775 .channels_min = 2,
2776 .channels_max = 2,
2779 #define alc260_pcm_digital_playback alc880_pcm_digital_playback
2780 #define alc260_pcm_digital_capture alc880_pcm_digital_capture
2783 * for BIOS auto-configuration
2786 static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
2787 const char *pfx)
2789 hda_nid_t nid_vol;
2790 unsigned long vol_val, sw_val;
2791 char name[32];
2792 int err;
2794 if (nid >= 0x0f && nid < 0x11) {
2795 nid_vol = nid - 0x7;
2796 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
2797 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
2798 } else if (nid == 0x11) {
2799 nid_vol = nid - 0x7;
2800 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT);
2801 sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
2802 } else if (nid >= 0x12 && nid <= 0x15) {
2803 nid_vol = 0x08;
2804 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
2805 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
2806 } else
2807 return 0; /* N/A */
2809 snprintf(name, sizeof(name), "%s Playback Volume", pfx);
2810 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name, vol_val)) < 0)
2811 return err;
2812 snprintf(name, sizeof(name), "%s Playback Switch", pfx);
2813 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, sw_val)) < 0)
2814 return err;
2815 return 1;
2818 /* add playback controls from the parsed DAC table */
2819 static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
2820 const struct auto_pin_cfg *cfg)
2822 hda_nid_t nid;
2823 int err;
2825 spec->multiout.num_dacs = 1;
2826 spec->multiout.dac_nids = spec->private_dac_nids;
2827 spec->multiout.dac_nids[0] = 0x02;
2829 nid = cfg->line_out_pins[0];
2830 if (nid) {
2831 err = alc260_add_playback_controls(spec, nid, "Front");
2832 if (err < 0)
2833 return err;
2836 nid = cfg->speaker_pin;
2837 if (nid) {
2838 err = alc260_add_playback_controls(spec, nid, "Speaker");
2839 if (err < 0)
2840 return err;
2843 nid = cfg->hp_pin;
2844 if (nid) {
2845 err = alc260_add_playback_controls(spec, nid, "Headphone");
2846 if (err < 0)
2847 return err;
2849 return 0;
2852 /* create playback/capture controls for input pins */
2853 static int alc260_auto_create_analog_input_ctls(struct alc_spec *spec,
2854 const struct auto_pin_cfg *cfg)
2856 struct hda_input_mux *imux = &spec->private_imux;
2857 int i, err, idx;
2859 for (i = 0; i < AUTO_PIN_LAST; i++) {
2860 if (cfg->input_pins[i] >= 0x12) {
2861 idx = cfg->input_pins[i] - 0x12;
2862 err = new_analog_input(spec, cfg->input_pins[i],
2863 auto_pin_cfg_labels[i], idx, 0x07);
2864 if (err < 0)
2865 return err;
2866 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
2867 imux->items[imux->num_items].index = idx;
2868 imux->num_items++;
2870 if ((cfg->input_pins[i] >= 0x0f) && (cfg->input_pins[i] <= 0x10)){
2871 idx = cfg->input_pins[i] - 0x09;
2872 err = new_analog_input(spec, cfg->input_pins[i],
2873 auto_pin_cfg_labels[i], idx, 0x07);
2874 if (err < 0)
2875 return err;
2876 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
2877 imux->items[imux->num_items].index = idx;
2878 imux->num_items++;
2881 return 0;
2884 static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
2885 hda_nid_t nid, int pin_type,
2886 int sel_idx)
2888 /* set as output */
2889 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
2890 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
2891 /* need the manual connection? */
2892 if (nid >= 0x12) {
2893 int idx = nid - 0x12;
2894 snd_hda_codec_write(codec, idx + 0x0b, 0,
2895 AC_VERB_SET_CONNECT_SEL, sel_idx);
2900 static void alc260_auto_init_multi_out(struct hda_codec *codec)
2902 struct alc_spec *spec = codec->spec;
2903 hda_nid_t nid;
2905 nid = spec->autocfg.line_out_pins[0];
2906 if (nid)
2907 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
2909 nid = spec->autocfg.speaker_pin;
2910 if (nid)
2911 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
2913 nid = spec->autocfg.hp_pin;
2914 if (nid)
2915 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
2918 #define ALC260_PIN_CD_NID 0x16
2919 static void alc260_auto_init_analog_input(struct hda_codec *codec)
2921 struct alc_spec *spec = codec->spec;
2922 int i;
2924 for (i = 0; i < AUTO_PIN_LAST; i++) {
2925 hda_nid_t nid = spec->autocfg.input_pins[i];
2926 if (nid >= 0x12) {
2927 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
2928 i <= AUTO_PIN_FRONT_MIC ? PIN_VREF80 : PIN_IN);
2929 if (nid != ALC260_PIN_CD_NID)
2930 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
2931 AMP_OUT_MUTE);
2937 * generic initialization of ADC, input mixers and output mixers
2939 static struct hda_verb alc260_volume_init_verbs[] = {
2941 * Unmute ADC0-1 and set the default input to mic-in
2943 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
2944 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2945 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
2946 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2948 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
2949 * mixer widget
2950 * Note: PASD motherboards uses the Line In 2 as the input for front panel
2951 * mic (mic 2)
2953 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
2954 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2955 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2956 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
2957 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
2958 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
2961 * Set up output mixers (0x08 - 0x0a)
2963 /* set vol=0 to output mixers */
2964 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2965 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2966 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2967 /* set up input amps for analog loopback */
2968 /* Amp Indices: DAC = 0, mixer = 1 */
2969 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2970 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2971 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2972 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2973 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2974 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2979 static int alc260_parse_auto_config(struct hda_codec *codec)
2981 struct alc_spec *spec = codec->spec;
2982 unsigned int wcap;
2983 int err;
2984 static hda_nid_t alc260_ignore[] = { 0x17, 0 };
2986 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
2987 alc260_ignore)) < 0)
2988 return err;
2989 if ((err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0)
2990 return err;
2991 if (! spec->kctl_alloc)
2992 return 0; /* can't find valid BIOS pin config */
2993 if ((err = alc260_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
2994 return err;
2996 spec->multiout.max_channels = 2;
2998 if (spec->autocfg.dig_out_pin)
2999 spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
3000 if (spec->kctl_alloc)
3001 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
3003 spec->init_verbs[spec->num_init_verbs++] = alc260_volume_init_verbs;
3005 spec->input_mux = &spec->private_imux;
3007 /* check whether NID 0x04 is valid */
3008 wcap = get_wcaps(codec, 0x04);
3009 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */
3010 if (wcap != AC_WID_AUD_IN) {
3011 spec->adc_nids = alc260_adc_nids_alt;
3012 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
3013 spec->mixers[spec->num_mixers] = alc260_capture_alt_mixer;
3014 } else {
3015 spec->adc_nids = alc260_adc_nids;
3016 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
3017 spec->mixers[spec->num_mixers] = alc260_capture_mixer;
3019 spec->num_mixers++;
3021 return 1;
3024 /* init callback for auto-configuration model -- overriding the default init */
3025 static int alc260_auto_init(struct hda_codec *codec)
3027 alc_init(codec);
3028 alc260_auto_init_multi_out(codec);
3029 alc260_auto_init_analog_input(codec);
3030 return 0;
3034 * ALC260 configurations
3036 static struct hda_board_config alc260_cfg_tbl[] = {
3037 { .modelname = "basic", .config = ALC260_BASIC },
3038 { .pci_subvendor = 0x104d, .pci_subdevice = 0x81bb,
3039 .config = ALC260_BASIC }, /* Sony VAIO */
3040 { .modelname = "hp", .config = ALC260_HP },
3041 { .pci_subvendor = 0x103c, .pci_subdevice = 0x3010, .config = ALC260_HP },
3042 { .pci_subvendor = 0x103c, .pci_subdevice = 0x3011, .config = ALC260_HP },
3043 { .pci_subvendor = 0x103c, .pci_subdevice = 0x3012, .config = ALC260_HP },
3044 { .pci_subvendor = 0x103c, .pci_subdevice = 0x3013, .config = ALC260_HP_3013 },
3045 { .pci_subvendor = 0x103c, .pci_subdevice = 0x3014, .config = ALC260_HP },
3046 { .pci_subvendor = 0x103c, .pci_subdevice = 0x3015, .config = ALC260_HP },
3047 { .pci_subvendor = 0x103c, .pci_subdevice = 0x3016, .config = ALC260_HP },
3048 { .modelname = "fujitsu", .config = ALC260_FUJITSU_S702X },
3049 { .pci_subvendor = 0x10cf, .pci_subdevice = 0x1326, .config = ALC260_FUJITSU_S702X },
3050 { .modelname = "auto", .config = ALC260_AUTO },
3054 static struct alc_config_preset alc260_presets[] = {
3055 [ALC260_BASIC] = {
3056 .mixers = { alc260_base_output_mixer,
3057 alc260_input_mixer,
3058 alc260_pc_beep_mixer,
3059 alc260_capture_mixer },
3060 .init_verbs = { alc260_init_verbs },
3061 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
3062 .dac_nids = alc260_dac_nids,
3063 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
3064 .adc_nids = alc260_adc_nids,
3065 .num_channel_mode = ARRAY_SIZE(alc260_modes),
3066 .channel_mode = alc260_modes,
3067 .input_mux = &alc260_capture_source,
3069 [ALC260_HP] = {
3070 .mixers = { alc260_base_output_mixer,
3071 alc260_input_mixer,
3072 alc260_capture_alt_mixer },
3073 .init_verbs = { alc260_hp_init_verbs },
3074 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
3075 .dac_nids = alc260_dac_nids,
3076 .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
3077 .adc_nids = alc260_hp_adc_nids,
3078 .num_channel_mode = ARRAY_SIZE(alc260_modes),
3079 .channel_mode = alc260_modes,
3080 .input_mux = &alc260_capture_source,
3082 [ALC260_HP_3013] = {
3083 .mixers = { alc260_hp_3013_mixer,
3084 alc260_input_mixer,
3085 alc260_capture_alt_mixer },
3086 .init_verbs = { alc260_hp_3013_init_verbs },
3087 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
3088 .dac_nids = alc260_dac_nids,
3089 .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
3090 .adc_nids = alc260_hp_adc_nids,
3091 .num_channel_mode = ARRAY_SIZE(alc260_modes),
3092 .channel_mode = alc260_modes,
3093 .input_mux = &alc260_capture_source,
3095 [ALC260_FUJITSU_S702X] = {
3096 .mixers = { alc260_fujitsu_mixer,
3097 alc260_capture_mixer },
3098 .init_verbs = { alc260_fujitsu_init_verbs },
3099 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
3100 .dac_nids = alc260_dac_nids,
3101 .num_adc_nids = ARRAY_SIZE(alc260_fujitsu_adc_nids),
3102 .adc_nids = alc260_fujitsu_adc_nids,
3103 .num_channel_mode = ARRAY_SIZE(alc260_modes),
3104 .channel_mode = alc260_modes,
3105 .input_mux = &alc260_fujitsu_capture_source,
3109 static int patch_alc260(struct hda_codec *codec)
3111 struct alc_spec *spec;
3112 int err, board_config;
3114 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3115 if (spec == NULL)
3116 return -ENOMEM;
3118 codec->spec = spec;
3120 board_config = snd_hda_check_board_config(codec, alc260_cfg_tbl);
3121 if (board_config < 0 || board_config >= ALC260_MODEL_LAST) {
3122 snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260\n");
3123 board_config = ALC260_AUTO;
3126 if (board_config == ALC260_AUTO) {
3127 /* automatic parse from the BIOS config */
3128 err = alc260_parse_auto_config(codec);
3129 if (err < 0) {
3130 alc_free(codec);
3131 return err;
3132 } else if (! err) {
3133 printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using base mode...\n");
3134 board_config = ALC260_BASIC;
3138 if (board_config != ALC260_AUTO)
3139 setup_preset(spec, &alc260_presets[board_config]);
3141 spec->stream_name_analog = "ALC260 Analog";
3142 spec->stream_analog_playback = &alc260_pcm_analog_playback;
3143 spec->stream_analog_capture = &alc260_pcm_analog_capture;
3145 spec->stream_name_digital = "ALC260 Digital";
3146 spec->stream_digital_playback = &alc260_pcm_digital_playback;
3147 spec->stream_digital_capture = &alc260_pcm_digital_capture;
3149 codec->patch_ops = alc_patch_ops;
3150 if (board_config == ALC260_AUTO)
3151 codec->patch_ops.init = alc260_auto_init;
3153 return 0;
3158 * ALC882 support
3160 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
3161 * configuration. Each pin widget can choose any input DACs and a mixer.
3162 * Each ADC is connected from a mixer of all inputs. This makes possible
3163 * 6-channel independent captures.
3165 * In addition, an independent DAC for the multi-playback (not used in this
3166 * driver yet).
3168 #define ALC882_DIGOUT_NID 0x06
3169 #define ALC882_DIGIN_NID 0x0a
3171 static struct hda_channel_mode alc882_ch_modes[1] = {
3172 { 8, NULL }
3175 static hda_nid_t alc882_dac_nids[4] = {
3176 /* front, rear, clfe, rear_surr */
3177 0x02, 0x03, 0x04, 0x05
3180 /* identical with ALC880 */
3181 #define alc882_adc_nids alc880_adc_nids
3182 #define alc882_adc_nids_alt alc880_adc_nids_alt
3184 /* input MUX */
3185 /* FIXME: should be a matrix-type input source selection */
3187 static struct hda_input_mux alc882_capture_source = {
3188 .num_items = 4,
3189 .items = {
3190 { "Mic", 0x0 },
3191 { "Front Mic", 0x1 },
3192 { "Line", 0x2 },
3193 { "CD", 0x4 },
3197 #define alc882_mux_enum_info alc_mux_enum_info
3198 #define alc882_mux_enum_get alc_mux_enum_get
3200 static int alc882_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
3202 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3203 struct alc_spec *spec = codec->spec;
3204 const struct hda_input_mux *imux = spec->input_mux;
3205 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
3206 static hda_nid_t capture_mixers[3] = { 0x24, 0x23, 0x22 };
3207 hda_nid_t nid = capture_mixers[adc_idx];
3208 unsigned int *cur_val = &spec->cur_mux[adc_idx];
3209 unsigned int i, idx;
3211 idx = ucontrol->value.enumerated.item[0];
3212 if (idx >= imux->num_items)
3213 idx = imux->num_items - 1;
3214 if (*cur_val == idx && ! codec->in_resume)
3215 return 0;
3216 for (i = 0; i < imux->num_items; i++) {
3217 unsigned int v = (i == idx) ? 0x7000 : 0x7080;
3218 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
3219 v | (imux->items[i].index << 8));
3221 *cur_val = idx;
3222 return 1;
3226 * 6ch mode
3228 static struct hda_verb alc882_sixstack_ch6_init[] = {
3229 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
3230 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
3231 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
3232 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
3233 { } /* end */
3237 * 8ch mode
3239 static struct hda_verb alc882_sixstack_ch8_init[] = {
3240 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
3241 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
3242 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
3243 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
3244 { } /* end */
3247 static struct hda_channel_mode alc882_sixstack_modes[2] = {
3248 { 6, alc882_sixstack_ch6_init },
3249 { 8, alc882_sixstack_ch8_init },
3252 /* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
3253 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
3255 static struct snd_kcontrol_new alc882_base_mixer[] = {
3256 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3257 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
3258 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
3259 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
3260 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
3261 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
3262 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
3263 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
3264 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
3265 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
3266 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
3267 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
3268 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
3269 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
3270 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
3271 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3272 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
3273 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3274 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
3275 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
3276 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
3277 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
3278 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
3279 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
3280 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
3281 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
3282 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
3284 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3285 /* .name = "Capture Source", */
3286 .name = "Input Source",
3287 .count = 3,
3288 .info = alc882_mux_enum_info,
3289 .get = alc882_mux_enum_get,
3290 .put = alc882_mux_enum_put,
3292 { } /* end */
3295 static struct snd_kcontrol_new alc882_chmode_mixer[] = {
3297 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3298 .name = "Channel Mode",
3299 .info = alc_ch_mode_info,
3300 .get = alc_ch_mode_get,
3301 .put = alc_ch_mode_put,
3303 { } /* end */
3306 static struct hda_verb alc882_init_verbs[] = {
3307 /* Front mixer: unmute input/output amp left and right (volume = 0) */
3308 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3309 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3310 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3311 /* Rear mixer */
3312 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3313 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3314 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3315 /* CLFE mixer */
3316 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3317 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3318 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3319 /* Side mixer */
3320 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3321 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3322 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3324 /* Front Pin: output 0 (0x0c) */
3325 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3326 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3327 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
3328 /* Rear Pin: output 1 (0x0d) */
3329 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3330 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3331 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
3332 /* CLFE Pin: output 2 (0x0e) */
3333 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3334 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3335 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
3336 /* Side Pin: output 3 (0x0f) */
3337 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3338 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3339 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
3340 /* Mic (rear) pin: input vref at 80% */
3341 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3342 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3343 /* Front Mic pin: input vref at 80% */
3344 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3345 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3346 /* Line In pin: input */
3347 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3348 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3349 /* Line-2 In: Headphone output (output 0 - 0x0c) */
3350 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3351 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3352 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
3353 /* CD pin widget for input */
3354 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3356 /* FIXME: use matrix-type input source selection */
3357 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
3358 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
3359 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3360 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3361 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3362 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
3363 /* Input mixer2 */
3364 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3365 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3366 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3367 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
3368 /* Input mixer3 */
3369 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3370 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3371 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3372 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
3373 /* ADC1: mute amp left and right */
3374 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3375 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
3376 /* ADC2: mute amp left and right */
3377 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3378 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
3379 /* ADC3: mute amp left and right */
3380 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3381 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
3387 * generic initialization of ADC, input mixers and output mixers
3389 static struct hda_verb alc882_auto_init_verbs[] = {
3391 * Unmute ADC0-2 and set the default input to mic-in
3393 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
3394 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3395 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
3396 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3397 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
3398 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3400 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
3401 * mixer widget
3402 * Note: PASD motherboards uses the Line In 2 as the input for front panel
3403 * mic (mic 2)
3405 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
3406 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3407 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3408 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
3409 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
3410 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
3413 * Set up output mixers (0x0c - 0x0f)
3415 /* set vol=0 to output mixers */
3416 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3417 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3418 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3419 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3420 /* set up input amps for analog loopback */
3421 /* Amp Indices: DAC = 0, mixer = 1 */
3422 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3423 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3424 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3425 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3426 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3427 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3428 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3429 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3430 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3431 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3433 /* FIXME: use matrix-type input source selection */
3434 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
3435 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
3436 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3437 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
3438 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
3439 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
3440 /* Input mixer2 */
3441 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3442 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
3443 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
3444 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
3445 /* Input mixer3 */
3446 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3447 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
3448 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
3449 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
3454 /* capture mixer elements */
3455 static struct snd_kcontrol_new alc882_capture_alt_mixer[] = {
3456 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
3457 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
3458 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
3459 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
3461 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3462 /* The multiple "Capture Source" controls confuse alsamixer
3463 * So call somewhat different..
3464 * FIXME: the controls appear in the "playback" view!
3466 /* .name = "Capture Source", */
3467 .name = "Input Source",
3468 .count = 2,
3469 .info = alc882_mux_enum_info,
3470 .get = alc882_mux_enum_get,
3471 .put = alc882_mux_enum_put,
3473 { } /* end */
3476 static struct snd_kcontrol_new alc882_capture_mixer[] = {
3477 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
3478 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
3479 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
3480 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
3481 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
3482 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
3484 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3485 /* The multiple "Capture Source" controls confuse alsamixer
3486 * So call somewhat different..
3487 * FIXME: the controls appear in the "playback" view!
3489 /* .name = "Capture Source", */
3490 .name = "Input Source",
3491 .count = 3,
3492 .info = alc882_mux_enum_info,
3493 .get = alc882_mux_enum_get,
3494 .put = alc882_mux_enum_put,
3496 { } /* end */
3499 /* pcm configuration: identiacal with ALC880 */
3500 #define alc882_pcm_analog_playback alc880_pcm_analog_playback
3501 #define alc882_pcm_analog_capture alc880_pcm_analog_capture
3502 #define alc882_pcm_digital_playback alc880_pcm_digital_playback
3503 #define alc882_pcm_digital_capture alc880_pcm_digital_capture
3506 * configuration and preset
3508 static struct hda_board_config alc882_cfg_tbl[] = {
3509 { .modelname = "3stack-dig", .config = ALC882_3ST_DIG },
3510 { .modelname = "6stack-dig", .config = ALC882_6ST_DIG },
3511 { .pci_subvendor = 0x1462, .pci_subdevice = 0x6668, .config = ALC882_6ST_DIG }, /* MSI */
3512 { .pci_subvendor = 0x105b, .pci_subdevice = 0x6668, .config = ALC882_6ST_DIG }, /* Foxconn */
3513 { .pci_subvendor = 0x1019, .pci_subdevice = 0x6668, .config = ALC882_6ST_DIG }, /* ECS */
3514 { .modelname = "auto", .config = ALC882_AUTO },
3518 static struct alc_config_preset alc882_presets[] = {
3519 [ALC882_3ST_DIG] = {
3520 .mixers = { alc882_base_mixer },
3521 .init_verbs = { alc882_init_verbs },
3522 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
3523 .dac_nids = alc882_dac_nids,
3524 .dig_out_nid = ALC882_DIGOUT_NID,
3525 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
3526 .adc_nids = alc882_adc_nids,
3527 .dig_in_nid = ALC882_DIGIN_NID,
3528 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
3529 .channel_mode = alc882_ch_modes,
3530 .input_mux = &alc882_capture_source,
3532 [ALC882_6ST_DIG] = {
3533 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
3534 .init_verbs = { alc882_init_verbs },
3535 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
3536 .dac_nids = alc882_dac_nids,
3537 .dig_out_nid = ALC882_DIGOUT_NID,
3538 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
3539 .adc_nids = alc882_adc_nids,
3540 .dig_in_nid = ALC882_DIGIN_NID,
3541 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
3542 .channel_mode = alc882_sixstack_modes,
3543 .input_mux = &alc882_capture_source,
3549 * BIOS auto configuration
3551 static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
3552 hda_nid_t nid, int pin_type,
3553 int dac_idx)
3555 /* set as output */
3556 struct alc_spec *spec = codec->spec;
3557 int idx;
3559 if (spec->multiout.dac_nids[dac_idx] == 0x25)
3560 idx = 4;
3561 else
3562 idx = spec->multiout.dac_nids[dac_idx] - 2;
3564 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
3565 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
3566 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
3570 static void alc882_auto_init_multi_out(struct hda_codec *codec)
3572 struct alc_spec *spec = codec->spec;
3573 int i;
3575 for (i = 0; i <= HDA_SIDE; i++) {
3576 hda_nid_t nid = spec->autocfg.line_out_pins[i];
3577 if (nid)
3578 alc882_auto_set_output_and_unmute(codec, nid, PIN_OUT, i);
3582 static void alc882_auto_init_hp_out(struct hda_codec *codec)
3584 struct alc_spec *spec = codec->spec;
3585 hda_nid_t pin;
3587 pin = spec->autocfg.hp_pin;
3588 if (pin) /* connect to front */
3589 alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); /* use dac 0 */
3592 #define alc882_is_input_pin(nid) alc880_is_input_pin(nid)
3593 #define ALC882_PIN_CD_NID ALC880_PIN_CD_NID
3595 static void alc882_auto_init_analog_input(struct hda_codec *codec)
3597 struct alc_spec *spec = codec->spec;
3598 int i;
3600 for (i = 0; i < AUTO_PIN_LAST; i++) {
3601 hda_nid_t nid = spec->autocfg.input_pins[i];
3602 if (alc882_is_input_pin(nid)) {
3603 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
3604 i <= AUTO_PIN_FRONT_MIC ? PIN_VREF80 : PIN_IN);
3605 if (nid != ALC882_PIN_CD_NID)
3606 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
3607 AMP_OUT_MUTE);
3612 /* almost identical with ALC880 parser... */
3613 static int alc882_parse_auto_config(struct hda_codec *codec)
3615 struct alc_spec *spec = codec->spec;
3616 int err = alc880_parse_auto_config(codec);
3618 if (err < 0)
3619 return err;
3620 else if (err > 0)
3621 /* hack - override the init verbs */
3622 spec->init_verbs[0] = alc882_auto_init_verbs;
3623 return err;
3626 /* init callback for auto-configuration model -- overriding the default init */
3627 static int alc882_auto_init(struct hda_codec *codec)
3629 alc_init(codec);
3630 alc882_auto_init_multi_out(codec);
3631 alc882_auto_init_hp_out(codec);
3632 alc882_auto_init_analog_input(codec);
3633 return 0;
3637 * ALC882 Headphone poll in 3.5.1a or 3.5.2
3640 static int patch_alc882(struct hda_codec *codec)
3642 struct alc_spec *spec;
3643 int err, board_config;
3645 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3646 if (spec == NULL)
3647 return -ENOMEM;
3649 codec->spec = spec;
3651 board_config = snd_hda_check_board_config(codec, alc882_cfg_tbl);
3653 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
3654 printk(KERN_INFO "hda_codec: Unknown model for ALC882, trying auto-probe from BIOS...\n");
3655 board_config = ALC882_AUTO;
3658 if (board_config == ALC882_AUTO) {
3659 /* automatic parse from the BIOS config */
3660 err = alc882_parse_auto_config(codec);
3661 if (err < 0) {
3662 alc_free(codec);
3663 return err;
3664 } else if (! err) {
3665 printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using base mode...\n");
3666 board_config = ALC882_3ST_DIG;
3670 if (board_config != ALC882_AUTO)
3671 setup_preset(spec, &alc882_presets[board_config]);
3673 spec->stream_name_analog = "ALC882 Analog";
3674 spec->stream_analog_playback = &alc882_pcm_analog_playback;
3675 spec->stream_analog_capture = &alc882_pcm_analog_capture;
3677 spec->stream_name_digital = "ALC882 Digital";
3678 spec->stream_digital_playback = &alc882_pcm_digital_playback;
3679 spec->stream_digital_capture = &alc882_pcm_digital_capture;
3681 if (! spec->adc_nids && spec->input_mux) {
3682 /* check whether NID 0x07 is valid */
3683 unsigned int wcap = get_wcaps(codec, 0x07);
3684 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */
3685 if (wcap != AC_WID_AUD_IN) {
3686 spec->adc_nids = alc882_adc_nids_alt;
3687 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids_alt);
3688 spec->mixers[spec->num_mixers] = alc882_capture_alt_mixer;
3689 spec->num_mixers++;
3690 } else {
3691 spec->adc_nids = alc882_adc_nids;
3692 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids);
3693 spec->mixers[spec->num_mixers] = alc882_capture_mixer;
3694 spec->num_mixers++;
3698 codec->patch_ops = alc_patch_ops;
3699 if (board_config == ALC882_AUTO)
3700 codec->patch_ops.init = alc882_auto_init;
3702 return 0;
3706 * ALC262 support
3709 #define ALC262_DIGOUT_NID ALC880_DIGOUT_NID
3710 #define ALC262_DIGIN_NID ALC880_DIGIN_NID
3712 #define alc262_dac_nids alc260_dac_nids
3713 #define alc262_adc_nids alc882_adc_nids
3714 #define alc262_adc_nids_alt alc882_adc_nids_alt
3716 #define alc262_modes alc260_modes
3717 #define alc262_capture_source alc882_capture_source
3719 static struct snd_kcontrol_new alc262_base_mixer[] = {
3720 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3721 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
3722 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
3723 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
3724 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
3725 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
3726 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3727 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
3728 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
3729 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
3730 /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
3731 HDA_CODEC_MUTE("PC Beelp Playback Switch", 0x0b, 0x05, HDA_INPUT), */
3732 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
3733 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
3734 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
3735 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
3736 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
3737 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
3739 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3740 .name = "Capture Source",
3741 .count = 1,
3742 .info = alc882_mux_enum_info,
3743 .get = alc882_mux_enum_get,
3744 .put = alc882_mux_enum_put,
3746 { } /* end */
3749 #define alc262_capture_mixer alc882_capture_mixer
3750 #define alc262_capture_alt_mixer alc882_capture_alt_mixer
3753 * generic initialization of ADC, input mixers and output mixers
3755 static struct hda_verb alc262_init_verbs[] = {
3757 * Unmute ADC0-2 and set the default input to mic-in
3759 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
3760 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3761 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
3762 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3763 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
3764 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3766 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
3767 * mixer widget
3768 * Note: PASD motherboards uses the Line In 2 as the input for front panel
3769 * mic (mic 2)
3771 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
3772 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3773 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3774 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
3775 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
3776 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
3779 * Set up output mixers (0x0c - 0x0e)
3781 /* set vol=0 to output mixers */
3782 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3783 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3784 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3785 /* set up input amps for analog loopback */
3786 /* Amp Indices: DAC = 0, mixer = 1 */
3787 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3788 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3789 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3790 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3791 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3792 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3794 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
3795 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
3796 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
3797 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
3798 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
3799 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
3801 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
3802 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
3803 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
3804 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
3805 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
3807 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
3808 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
3810 /* FIXME: use matrix-type input source selection */
3811 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
3812 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
3813 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3814 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
3815 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
3816 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
3817 /* Input mixer2 */
3818 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3819 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
3820 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
3821 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
3822 /* Input mixer3 */
3823 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3824 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
3825 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
3826 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
3831 /* add playback controls from the parsed DAC table */
3832 static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg)
3834 hda_nid_t nid;
3835 int err;
3837 spec->multiout.num_dacs = 1; /* only use one dac */
3838 spec->multiout.dac_nids = spec->private_dac_nids;
3839 spec->multiout.dac_nids[0] = 2;
3841 nid = cfg->line_out_pins[0];
3842 if (nid) {
3843 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Front Playback Volume",
3844 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT))) < 0)
3845 return err;
3846 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Front Playback Switch",
3847 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
3848 return err;
3851 nid = cfg->speaker_pin;
3852 if (nid) {
3853 if (nid == 0x16) {
3854 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Speaker Playback Volume",
3855 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT))) < 0)
3856 return err;
3857 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Speaker Playback Switch",
3858 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0)
3859 return err;
3860 } else {
3861 if (! cfg->line_out_pins[0])
3862 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Speaker Playback Volume",
3863 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT))) < 0)
3864 return err;
3865 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Speaker Playback Switch",
3866 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
3867 return err;
3870 nid = cfg->hp_pin;
3871 if (nid) {
3872 /* spec->multiout.hp_nid = 2; */
3873 if (nid == 0x16) {
3874 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Headphone Playback Volume",
3875 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT))) < 0)
3876 return err;
3877 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Headphone Playback Switch",
3878 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0)
3879 return err;
3880 } else {
3881 if (! cfg->line_out_pins[0])
3882 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Headphone Playback Volume",
3883 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT))) < 0)
3884 return err;
3885 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Headphone Playback Switch",
3886 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
3887 return err;
3890 return 0;
3893 /* identical with ALC880 */
3894 #define alc262_auto_create_analog_input_ctls alc880_auto_create_analog_input_ctls
3897 * generic initialization of ADC, input mixers and output mixers
3899 static struct hda_verb alc262_volume_init_verbs[] = {
3901 * Unmute ADC0-2 and set the default input to mic-in
3903 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
3904 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3905 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
3906 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3907 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
3908 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3910 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
3911 * mixer widget
3912 * Note: PASD motherboards uses the Line In 2 as the input for front panel
3913 * mic (mic 2)
3915 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
3916 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3917 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3918 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
3919 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
3920 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
3923 * Set up output mixers (0x0c - 0x0f)
3925 /* set vol=0 to output mixers */
3926 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3927 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3928 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3930 /* set up input amps for analog loopback */
3931 /* Amp Indices: DAC = 0, mixer = 1 */
3932 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3933 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3934 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3935 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3936 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3937 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3939 /* FIXME: use matrix-type input source selection */
3940 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
3941 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
3942 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3943 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
3944 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
3945 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
3946 /* Input mixer2 */
3947 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3948 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
3949 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
3950 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
3951 /* Input mixer3 */
3952 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3953 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
3954 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
3955 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
3960 /* pcm configuration: identiacal with ALC880 */
3961 #define alc262_pcm_analog_playback alc880_pcm_analog_playback
3962 #define alc262_pcm_analog_capture alc880_pcm_analog_capture
3963 #define alc262_pcm_digital_playback alc880_pcm_digital_playback
3964 #define alc262_pcm_digital_capture alc880_pcm_digital_capture
3967 * BIOS auto configuration
3969 static int alc262_parse_auto_config(struct hda_codec *codec)
3971 struct alc_spec *spec = codec->spec;
3972 int err;
3973 static hda_nid_t alc262_ignore[] = { 0x1d, 0 };
3975 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
3976 alc262_ignore)) < 0)
3977 return err;
3978 if (! spec->autocfg.line_outs && ! spec->autocfg.speaker_pin &&
3979 ! spec->autocfg.hp_pin)
3980 return 0; /* can't find valid BIOS pin config */
3981 if ((err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 ||
3982 (err = alc262_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
3983 return err;
3985 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
3987 if (spec->autocfg.dig_out_pin)
3988 spec->multiout.dig_out_nid = ALC262_DIGOUT_NID;
3989 if (spec->autocfg.dig_in_pin)
3990 spec->dig_in_nid = ALC262_DIGIN_NID;
3992 if (spec->kctl_alloc)
3993 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
3995 spec->init_verbs[spec->num_init_verbs++] = alc262_volume_init_verbs;
3996 spec->input_mux = &spec->private_imux;
3998 return 1;
4001 #define alc262_auto_init_multi_out alc882_auto_init_multi_out
4002 #define alc262_auto_init_hp_out alc882_auto_init_hp_out
4003 #define alc262_auto_init_analog_input alc882_auto_init_analog_input
4006 /* init callback for auto-configuration model -- overriding the default init */
4007 static int alc262_auto_init(struct hda_codec *codec)
4009 alc_init(codec);
4010 alc262_auto_init_multi_out(codec);
4011 alc262_auto_init_hp_out(codec);
4012 alc262_auto_init_analog_input(codec);
4013 return 0;
4017 * configuration and preset
4019 static struct hda_board_config alc262_cfg_tbl[] = {
4020 { .modelname = "basic", .config = ALC262_BASIC },
4021 { .modelname = "auto", .config = ALC262_AUTO },
4025 static struct alc_config_preset alc262_presets[] = {
4026 [ALC262_BASIC] = {
4027 .mixers = { alc262_base_mixer },
4028 .init_verbs = { alc262_init_verbs },
4029 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
4030 .dac_nids = alc262_dac_nids,
4031 .hp_nid = 0x03,
4032 .num_channel_mode = ARRAY_SIZE(alc262_modes),
4033 .channel_mode = alc262_modes,
4034 .input_mux = &alc262_capture_source,
4038 static int patch_alc262(struct hda_codec *codec)
4040 struct alc_spec *spec;
4041 int board_config;
4042 int err;
4044 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
4045 if (spec == NULL)
4046 return -ENOMEM;
4048 codec->spec = spec;
4049 #if 0
4050 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is under-run */
4052 int tmp;
4053 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
4054 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
4055 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
4056 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
4058 #endif
4060 board_config = snd_hda_check_board_config(codec, alc262_cfg_tbl);
4061 if (board_config < 0 || board_config >= ALC262_MODEL_LAST) {
4062 printk(KERN_INFO "hda_codec: Unknown model for ALC262, trying auto-probe from BIOS...\n");
4063 board_config = ALC262_AUTO;
4066 if (board_config == ALC262_AUTO) {
4067 /* automatic parse from the BIOS config */
4068 err = alc262_parse_auto_config(codec);
4069 if (err < 0) {
4070 alc_free(codec);
4071 return err;
4072 } else if (! err) {
4073 printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using base mode...\n");
4074 board_config = ALC262_BASIC;
4078 if (board_config != ALC262_AUTO)
4079 setup_preset(spec, &alc262_presets[board_config]);
4081 spec->stream_name_analog = "ALC262 Analog";
4082 spec->stream_analog_playback = &alc262_pcm_analog_playback;
4083 spec->stream_analog_capture = &alc262_pcm_analog_capture;
4085 spec->stream_name_digital = "ALC262 Digital";
4086 spec->stream_digital_playback = &alc262_pcm_digital_playback;
4087 spec->stream_digital_capture = &alc262_pcm_digital_capture;
4089 if (! spec->adc_nids && spec->input_mux) {
4090 /* check whether NID 0x07 is valid */
4091 unsigned int wcap = get_wcaps(codec, 0x07);
4093 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */
4094 if (wcap != AC_WID_AUD_IN) {
4095 spec->adc_nids = alc262_adc_nids_alt;
4096 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids_alt);
4097 spec->mixers[spec->num_mixers] = alc262_capture_alt_mixer;
4098 spec->num_mixers++;
4099 } else {
4100 spec->adc_nids = alc262_adc_nids;
4101 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids);
4102 spec->mixers[spec->num_mixers] = alc262_capture_mixer;
4103 spec->num_mixers++;
4107 codec->patch_ops = alc_patch_ops;
4108 if (board_config == ALC262_AUTO)
4109 codec->patch_ops.init = alc262_auto_init;
4111 return 0;
4116 * ALC861 channel source setting (2/6 channel selection for 3-stack)
4120 * set the path ways for 2 channel output
4121 * need to set the codec line out and mic 1 pin widgets to inputs
4123 static struct hda_verb alc861_threestack_ch2_init[] = {
4124 /* set pin widget 1Ah (line in) for input */
4125 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
4126 /* set pin widget 18h (mic1/2) for input, for mic also enable the vref */
4127 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
4129 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
4130 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, //mic
4131 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, //line in
4132 { } /* end */
4135 * 6ch mode
4136 * need to set the codec line out and mic 1 pin widgets to outputs
4138 static struct hda_verb alc861_threestack_ch6_init[] = {
4139 /* set pin widget 1Ah (line in) for output (Back Surround)*/
4140 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
4141 /* set pin widget 18h (mic1) for output (CLFE)*/
4142 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
4144 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
4145 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
4147 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
4148 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, //mic
4149 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, //line in
4150 { } /* end */
4153 static struct hda_channel_mode alc861_threestack_modes[2] = {
4154 { 2, alc861_threestack_ch2_init },
4155 { 6, alc861_threestack_ch6_init },
4158 /* patch-ALC861 */
4160 static struct snd_kcontrol_new alc861_base_mixer[] = {
4161 /* output mixer control */
4162 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
4163 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
4164 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
4165 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
4166 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
4168 /*Input mixer control */
4169 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
4170 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
4171 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
4172 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
4173 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
4174 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
4175 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
4176 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
4177 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
4178 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
4180 /* Capture mixer control */
4181 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
4182 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
4184 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4185 .name = "Capture Source",
4186 .count = 1,
4187 .info = alc_mux_enum_info,
4188 .get = alc_mux_enum_get,
4189 .put = alc_mux_enum_put,
4191 { } /* end */
4194 static struct snd_kcontrol_new alc861_3ST_mixer[] = {
4195 /* output mixer control */
4196 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
4197 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
4198 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
4199 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
4200 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
4202 /* Input mixer control */
4203 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
4204 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
4205 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
4206 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
4207 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
4208 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
4209 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
4210 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
4211 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
4212 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
4214 /* Capture mixer control */
4215 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
4216 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
4218 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4219 .name = "Capture Source",
4220 .count = 1,
4221 .info = alc_mux_enum_info,
4222 .get = alc_mux_enum_get,
4223 .put = alc_mux_enum_put,
4226 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4227 .name = "Channel Mode",
4228 .info = alc_ch_mode_info,
4229 .get = alc_ch_mode_get,
4230 .put = alc_ch_mode_put,
4231 .private_value = ARRAY_SIZE(alc861_threestack_modes),
4233 { } /* end */
4237 * generic initialization of ADC, input mixers and output mixers
4239 static struct hda_verb alc861_base_init_verbs[] = {
4241 * Unmute ADC0 and set the default input to mic-in
4243 /* port-A for surround (rear panel) */
4244 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
4245 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
4246 /* port-B for mic-in (rear panel) with vref */
4247 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
4248 /* port-C for line-in (rear panel) */
4249 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
4250 /* port-D for Front */
4251 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
4252 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
4253 /* port-E for HP out (front panel) */
4254 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
4255 /* route front PCM to HP */
4256 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01 },
4257 /* port-F for mic-in (front panel) with vref */
4258 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
4259 /* port-G for CLFE (rear panel) */
4260 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
4261 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
4262 /* port-H for side (rear panel) */
4263 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
4264 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
4265 /* CD-in */
4266 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
4267 /* route front mic to ADC1*/
4268 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
4269 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4271 /* Unmute DAC0~3 & spdif out*/
4272 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4273 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4274 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4275 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4276 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4278 /* Unmute Mixer 14 (mic) 1c (Line in)*/
4279 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4280 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4281 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4282 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4284 /* Unmute Stereo Mixer 15 */
4285 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4286 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4287 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
4288 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c }, //Output 0~12 step
4290 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4291 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4292 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4293 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4294 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4295 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4296 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4297 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4298 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, // hp used DAC 3 (Front)
4299 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
4304 static struct hda_verb alc861_threestack_init_verbs[] = {
4306 * Unmute ADC0 and set the default input to mic-in
4308 /* port-A for surround (rear panel) */
4309 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
4310 /* port-B for mic-in (rear panel) with vref */
4311 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
4312 /* port-C for line-in (rear panel) */
4313 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
4314 /* port-D for Front */
4315 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
4316 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
4317 /* port-E for HP out (front panel) */
4318 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
4319 /* route front PCM to HP */
4320 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01 },
4321 /* port-F for mic-in (front panel) with vref */
4322 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
4323 /* port-G for CLFE (rear panel) */
4324 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
4325 /* port-H for side (rear panel) */
4326 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
4327 /* CD-in */
4328 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
4329 /* route front mic to ADC1*/
4330 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
4331 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4332 /* Unmute DAC0~3 & spdif out*/
4333 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4334 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4335 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4336 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4337 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4339 /* Unmute Mixer 14 (mic) 1c (Line in)*/
4340 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4341 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4342 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4343 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4345 /* Unmute Stereo Mixer 15 */
4346 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4347 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4348 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
4349 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c }, //Output 0~12 step
4351 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4352 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4353 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4354 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4355 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4356 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4357 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4358 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4359 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, // hp used DAC 3 (Front)
4360 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
4364 * generic initialization of ADC, input mixers and output mixers
4366 static struct hda_verb alc861_auto_init_verbs[] = {
4368 * Unmute ADC0 and set the default input to mic-in
4370 // {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
4371 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4373 /* Unmute DAC0~3 & spdif out*/
4374 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4375 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4376 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4377 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4378 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4380 /* Unmute Mixer 14 (mic) 1c (Line in)*/
4381 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4382 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4383 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4384 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4386 /* Unmute Stereo Mixer 15 */
4387 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4388 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4389 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
4390 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
4392 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4393 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4394 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4395 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4396 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4397 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4398 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4399 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4401 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4402 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4403 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
4404 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
4405 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4406 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4407 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
4408 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
4410 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, // set Mic 1
4415 /* pcm configuration: identiacal with ALC880 */
4416 #define alc861_pcm_analog_playback alc880_pcm_analog_playback
4417 #define alc861_pcm_analog_capture alc880_pcm_analog_capture
4418 #define alc861_pcm_digital_playback alc880_pcm_digital_playback
4419 #define alc861_pcm_digital_capture alc880_pcm_digital_capture
4422 #define ALC861_DIGOUT_NID 0x07
4424 static struct hda_channel_mode alc861_8ch_modes[1] = {
4425 { 8, NULL }
4428 static hda_nid_t alc861_dac_nids[4] = {
4429 /* front, surround, clfe, side */
4430 0x03, 0x06, 0x05, 0x04
4433 static hda_nid_t alc861_adc_nids[1] = {
4434 /* ADC0-2 */
4435 0x08,
4438 static struct hda_input_mux alc861_capture_source = {
4439 .num_items = 5,
4440 .items = {
4441 { "Mic", 0x0 },
4442 { "Front Mic", 0x3 },
4443 { "Line", 0x1 },
4444 { "CD", 0x4 },
4445 { "Mixer", 0x5 },
4449 /* fill in the dac_nids table from the parsed pin configuration */
4450 static int alc861_auto_fill_dac_nids(struct alc_spec *spec, const struct auto_pin_cfg *cfg)
4452 int i;
4453 hda_nid_t nid;
4455 spec->multiout.dac_nids = spec->private_dac_nids;
4456 for (i = 0; i < cfg->line_outs; i++) {
4457 nid = cfg->line_out_pins[i];
4458 if (nid) {
4459 if (i >= ARRAY_SIZE(alc861_dac_nids))
4460 continue;
4461 spec->multiout.dac_nids[i] = alc861_dac_nids[i];
4464 spec->multiout.num_dacs = cfg->line_outs;
4465 return 0;
4468 /* add playback controls from the parsed DAC table */
4469 static int alc861_auto_create_multi_out_ctls(struct alc_spec *spec,
4470 const struct auto_pin_cfg *cfg)
4472 char name[32];
4473 static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" };
4474 hda_nid_t nid;
4475 int i, idx, err;
4477 for (i = 0; i < cfg->line_outs; i++) {
4478 nid = spec->multiout.dac_nids[i];
4479 if (! nid)
4480 continue;
4481 if (nid == 0x05) {
4482 /* Center/LFE */
4483 if ((err = add_control(spec, ALC_CTL_BIND_MUTE, "Center Playback Switch",
4484 HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT))) < 0)
4485 return err;
4486 if ((err = add_control(spec, ALC_CTL_BIND_MUTE, "LFE Playback Switch",
4487 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0)
4488 return err;
4489 } else {
4490 for (idx = 0; idx < ARRAY_SIZE(alc861_dac_nids) - 1; idx++)
4491 if (nid == alc861_dac_nids[idx])
4492 break;
4493 sprintf(name, "%s Playback Switch", chname[idx]);
4494 if ((err = add_control(spec, ALC_CTL_BIND_MUTE, name,
4495 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
4496 return err;
4499 return 0;
4502 static int alc861_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin)
4504 int err;
4505 hda_nid_t nid;
4507 if (! pin)
4508 return 0;
4510 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
4511 nid = 0x03;
4512 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Headphone Playback Switch",
4513 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
4514 return err;
4515 spec->multiout.hp_nid = nid;
4517 return 0;
4520 /* create playback/capture controls for input pins */
4521 static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg)
4523 struct hda_input_mux *imux = &spec->private_imux;
4524 int i, err, idx, idx1;
4526 for (i = 0; i < AUTO_PIN_LAST; i++) {
4527 switch(cfg->input_pins[i]) {
4528 case 0x0c:
4529 idx1 = 1;
4530 idx = 2; // Line In
4531 break;
4532 case 0x0f:
4533 idx1 = 2;
4534 idx = 2; // Line In
4535 break;
4536 case 0x0d:
4537 idx1 = 0;
4538 idx = 1; // Mic In
4539 break;
4540 case 0x10:
4541 idx1 = 3;
4542 idx = 1; // Mic In
4543 break;
4544 case 0x11:
4545 idx1 = 4;
4546 idx = 0; // CD
4547 break;
4548 default:
4549 continue;
4552 err = new_analog_input(spec, cfg->input_pins[i],
4553 auto_pin_cfg_labels[i], idx, 0x15);
4554 if (err < 0)
4555 return err;
4557 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
4558 imux->items[imux->num_items].index = idx1;
4559 imux->num_items++;
4561 return 0;
4564 static struct snd_kcontrol_new alc861_capture_mixer[] = {
4565 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
4566 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
4569 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4570 /* The multiple "Capture Source" controls confuse alsamixer
4571 * So call somewhat different..
4572 *FIXME: the controls appear in the "playback" view!
4574 /* .name = "Capture Source", */
4575 .name = "Input Source",
4576 .count = 1,
4577 .info = alc_mux_enum_info,
4578 .get = alc_mux_enum_get,
4579 .put = alc_mux_enum_put,
4581 { } /* end */
4584 static void alc861_auto_set_output_and_unmute(struct hda_codec *codec, hda_nid_t nid,
4585 int pin_type, int dac_idx)
4587 /* set as output */
4589 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
4590 snd_hda_codec_write(codec, dac_idx, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
4594 static void alc861_auto_init_multi_out(struct hda_codec *codec)
4596 struct alc_spec *spec = codec->spec;
4597 int i;
4599 for (i = 0; i < spec->autocfg.line_outs; i++) {
4600 hda_nid_t nid = spec->autocfg.line_out_pins[i];
4601 if (nid)
4602 alc861_auto_set_output_and_unmute(codec, nid, PIN_OUT, spec->multiout.dac_nids[i]);
4606 static void alc861_auto_init_hp_out(struct hda_codec *codec)
4608 struct alc_spec *spec = codec->spec;
4609 hda_nid_t pin;
4611 pin = spec->autocfg.hp_pin;
4612 if (pin) /* connect to front */
4613 alc861_auto_set_output_and_unmute(codec, pin, PIN_HP, spec->multiout.dac_nids[0]);
4616 static void alc861_auto_init_analog_input(struct hda_codec *codec)
4618 struct alc_spec *spec = codec->spec;
4619 int i;
4621 for (i = 0; i < AUTO_PIN_LAST; i++) {
4622 hda_nid_t nid = spec->autocfg.input_pins[i];
4623 if ((nid>=0x0c) && (nid <=0x11)) {
4624 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4625 i <= AUTO_PIN_FRONT_MIC ? PIN_VREF80 : PIN_IN);
4630 /* parse the BIOS configuration and set up the alc_spec */
4631 /* return 1 if successful, 0 if the proper config is not found, or a negative error code */
4632 static int alc861_parse_auto_config(struct hda_codec *codec)
4634 struct alc_spec *spec = codec->spec;
4635 int err;
4636 static hda_nid_t alc861_ignore[] = { 0x1d, 0 };
4638 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
4639 alc861_ignore)) < 0)
4640 return err;
4641 if (! spec->autocfg.line_outs && ! spec->autocfg.speaker_pin &&
4642 ! spec->autocfg.hp_pin)
4643 return 0; /* can't find valid BIOS pin config */
4645 if ((err = alc861_auto_fill_dac_nids(spec, &spec->autocfg)) < 0 ||
4646 (err = alc861_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 ||
4647 (err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pin)) < 0 ||
4648 (err = alc861_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
4649 return err;
4651 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
4653 if (spec->autocfg.dig_out_pin)
4654 spec->multiout.dig_out_nid = ALC861_DIGOUT_NID;
4656 if (spec->kctl_alloc)
4657 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
4659 spec->init_verbs[spec->num_init_verbs++] = alc861_auto_init_verbs;
4661 spec->input_mux = &spec->private_imux;
4663 spec->adc_nids = alc861_adc_nids;
4664 spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
4665 spec->mixers[spec->num_mixers] = alc861_capture_mixer;
4666 spec->num_mixers++;
4668 return 1;
4671 /* init callback for auto-configuration model -- overriding the default init */
4672 static int alc861_auto_init(struct hda_codec *codec)
4674 alc_init(codec);
4675 alc861_auto_init_multi_out(codec);
4676 alc861_auto_init_hp_out(codec);
4677 alc861_auto_init_analog_input(codec);
4679 return 0;
4684 * configuration and preset
4686 static struct hda_board_config alc861_cfg_tbl[] = {
4687 { .modelname = "3stack", .config = ALC861_3ST },
4688 { .pci_subvendor = 0x8086, .pci_subdevice = 0xd600, .config = ALC861_3ST },
4689 { .modelname = "3stack-dig", .config = ALC861_3ST_DIG },
4690 { .modelname = "6stack-dig", .config = ALC861_6ST_DIG },
4691 { .modelname = "auto", .config = ALC861_AUTO },
4695 static struct alc_config_preset alc861_presets[] = {
4696 [ALC861_3ST] = {
4697 .mixers = { alc861_3ST_mixer },
4698 .init_verbs = { alc861_threestack_init_verbs },
4699 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
4700 .dac_nids = alc861_dac_nids,
4701 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
4702 .channel_mode = alc861_threestack_modes,
4703 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
4704 .adc_nids = alc861_adc_nids,
4705 .input_mux = &alc861_capture_source,
4707 [ALC861_3ST_DIG] = {
4708 .mixers = { alc861_base_mixer },
4709 .init_verbs = { alc861_threestack_init_verbs },
4710 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
4711 .dac_nids = alc861_dac_nids,
4712 .dig_out_nid = ALC861_DIGOUT_NID,
4713 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
4714 .channel_mode = alc861_threestack_modes,
4715 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
4716 .adc_nids = alc861_adc_nids,
4717 .input_mux = &alc861_capture_source,
4719 [ALC861_6ST_DIG] = {
4720 .mixers = { alc861_base_mixer },
4721 .init_verbs = { alc861_base_init_verbs },
4722 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
4723 .dac_nids = alc861_dac_nids,
4724 .dig_out_nid = ALC861_DIGOUT_NID,
4725 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
4726 .channel_mode = alc861_8ch_modes,
4727 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
4728 .adc_nids = alc861_adc_nids,
4729 .input_mux = &alc861_capture_source,
4734 static int patch_alc861(struct hda_codec *codec)
4736 struct alc_spec *spec;
4737 int board_config;
4738 int err;
4740 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
4741 if (spec == NULL)
4742 return -ENOMEM;
4744 codec->spec = spec;
4746 board_config = snd_hda_check_board_config(codec, alc861_cfg_tbl);
4747 if (board_config < 0 || board_config >= ALC861_MODEL_LAST) {
4748 printk(KERN_INFO "hda_codec: Unknown model for ALC861, trying auto-probe from BIOS...\n");
4749 board_config = ALC861_AUTO;
4752 if (board_config == ALC861_AUTO) {
4753 /* automatic parse from the BIOS config */
4754 err = alc861_parse_auto_config(codec);
4755 if (err < 0) {
4756 alc_free(codec);
4757 return err;
4758 } else if (! err) {
4759 printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using base mode...\n");
4760 board_config = ALC861_3ST_DIG;
4764 if (board_config != ALC861_AUTO)
4765 setup_preset(spec, &alc861_presets[board_config]);
4767 spec->stream_name_analog = "ALC861 Analog";
4768 spec->stream_analog_playback = &alc861_pcm_analog_playback;
4769 spec->stream_analog_capture = &alc861_pcm_analog_capture;
4771 spec->stream_name_digital = "ALC861 Digital";
4772 spec->stream_digital_playback = &alc861_pcm_digital_playback;
4773 spec->stream_digital_capture = &alc861_pcm_digital_capture;
4775 codec->patch_ops = alc_patch_ops;
4776 if (board_config == ALC861_AUTO)
4777 codec->patch_ops.init = alc861_auto_init;
4779 return 0;
4783 * patch entries
4785 struct hda_codec_preset snd_hda_preset_realtek[] = {
4786 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
4787 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
4788 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
4789 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
4790 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 },
4791 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
4792 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
4793 {} /* terminator */