]> git.ipfire.org Git - thirdparty/kernel/stable.git/blame - sound/pci/hda/patch_realtek.c
[ALSA] hda-codec - Show power state in proc file
[thirdparty/kernel/stable.git] / sound / pci / hda / patch_realtek.c
CommitLineData
1da177e4
LT
1/*
2 * Universal Interface for Intel High Definition Audio Codec
3 *
4 * HD audio interface patch for ALC 260/880/882 codecs
5 *
6 * Copyright (c) 2004 PeiSen Hou <pshou@realtek.com.tw>
7 * Takashi Iwai <tiwai@suse.de>
8 *
9 * This driver is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This driver is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24#include <sound/driver.h>
25#include <linux/init.h>
26#include <linux/delay.h>
27#include <linux/slab.h>
28#include <linux/pci.h>
29#include <sound/core.h>
30#include "hda_codec.h"
31#include "hda_local.h"
32
33
34/* ALC880 board config type */
35enum {
1da177e4
LT
36 ALC880_3ST,
37 ALC880_3ST_DIG,
38 ALC880_5ST,
39 ALC880_5ST_DIG,
40 ALC880_W810,
dfc0ff62 41 ALC880_Z71V,
e9edcee0 42 ALC880_AUTO,
b6482d48 43 ALC880_6ST,
16ded525
TI
44 ALC880_6ST_DIG,
45 ALC880_F1734,
46 ALC880_ASUS,
47 ALC880_ASUS_DIG,
48 ALC880_ASUS_W1V,
49 ALC880_UNIWILL_DIG,
e9edcee0
TI
50#ifdef CONFIG_SND_DEBUG
51 ALC880_TEST,
52#endif
16ded525
TI
53 ALC880_MODEL_LAST /* last tag */
54};
55
56/* ALC260 models */
57enum {
58 ALC260_BASIC,
59 ALC260_HP,
a9430dd8 60 ALC260_FUJITSU_S702x,
16ded525 61 ALC260_MODEL_LAST /* last tag */
1da177e4
LT
62};
63
e9edcee0
TI
64/* amp values */
65#define AMP_IN_MUTE(idx) (0x7080 | ((idx)<<8))
66#define AMP_IN_UNMUTE(idx) (0x7000 | ((idx)<<8))
67#define AMP_OUT_MUTE 0xb080
68#define AMP_OUT_UNMUTE 0xb000
69#define AMP_OUT_ZERO 0xb000
70/* pinctl values */
71#define PIN_IN 0x20
72#define PIN_VREF80 0x24
73#define PIN_VREF50 0x21
74#define PIN_OUT 0x40
75#define PIN_HP 0xc0
a9430dd8 76#define PIN_HP_AMP 0x80
e9edcee0 77
1da177e4
LT
78struct alc_spec {
79 /* codec parameterization */
e9edcee0 80 snd_kcontrol_new_t *mixers[3]; /* mixer arrays */
1da177e4
LT
81 unsigned int num_mixers;
82
e9edcee0
TI
83 const struct hda_verb *init_verbs[3]; /* initialization verbs
84 * don't forget NULL termination!
85 */
86 unsigned int num_init_verbs;
1da177e4 87
16ded525 88 char *stream_name_analog; /* analog PCM stream */
1da177e4
LT
89 struct hda_pcm_stream *stream_analog_playback;
90 struct hda_pcm_stream *stream_analog_capture;
91
16ded525 92 char *stream_name_digital; /* digital PCM stream */
1da177e4
LT
93 struct hda_pcm_stream *stream_digital_playback;
94 struct hda_pcm_stream *stream_digital_capture;
95
96 /* playback */
16ded525
TI
97 struct hda_multi_out multiout; /* playback set-up
98 * max_channels, dacs must be set
99 * dig_out_nid and hp_nid are optional
100 */
1da177e4
LT
101
102 /* capture */
103 unsigned int num_adc_nids;
104 hda_nid_t *adc_nids;
16ded525 105 hda_nid_t dig_in_nid; /* digital-in NID; optional */
1da177e4
LT
106
107 /* capture source */
108 const struct hda_input_mux *input_mux;
109 unsigned int cur_mux[3];
110
111 /* channel model */
112 const struct alc_channel_mode *channel_mode;
113 int num_channel_mode;
114
115 /* PCM information */
16ded525 116 struct hda_pcm pcm_rec[2]; /* used in alc_build_pcms() */
41e41f1f 117
16ded525 118 struct semaphore bind_mutex; /* for bound controls */
16ded525 119
e9edcee0
TI
120 /* dynamic controls, init_verbs and input_mux */
121 struct auto_pin_cfg autocfg;
122 unsigned int num_kctl_alloc, num_kctl_used;
123 snd_kcontrol_new_t *kctl_alloc;
124 struct hda_input_mux private_imux;
b0af0de5 125 hda_nid_t private_dac_nids[4];
1da177e4
LT
126};
127
1da177e4
LT
128
129/*
130 * input MUX handling
131 */
132static int alc_mux_enum_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
133{
134 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
135 struct alc_spec *spec = codec->spec;
136 return snd_hda_input_mux_info(spec->input_mux, uinfo);
137}
138
139static int alc_mux_enum_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
140{
141 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
142 struct alc_spec *spec = codec->spec;
143 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
144
145 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
146 return 0;
147}
148
149static int alc_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
150{
151 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
152 struct alc_spec *spec = codec->spec;
153 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
154 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
155 spec->adc_nids[adc_idx], &spec->cur_mux[adc_idx]);
156}
157
e9edcee0 158
1da177e4
LT
159/*
160 * channel mode setting
161 */
162struct alc_channel_mode {
163 int channels;
164 const struct hda_verb *sequence;
165};
166
1da177e4
LT
167static int alc880_ch_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
168{
169 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
170 struct alc_spec *spec = codec->spec;
fd2c326d 171 int items = kcontrol->private_value ? (int)kcontrol->private_value : 2;
1da177e4
LT
172
173 snd_assert(spec->channel_mode, return -ENXIO);
174 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
175 uinfo->count = 1;
fd2c326d
TI
176 uinfo->value.enumerated.items = items;
177 if (uinfo->value.enumerated.item >= items)
178 uinfo->value.enumerated.item = items - 1;
1da177e4
LT
179 sprintf(uinfo->value.enumerated.name, "%dch",
180 spec->channel_mode[uinfo->value.enumerated.item].channels);
181 return 0;
182}
183
184static int alc880_ch_mode_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
185{
186 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
187 struct alc_spec *spec = codec->spec;
fd2c326d
TI
188 int items = kcontrol->private_value ? (int)kcontrol->private_value : 2;
189 int i;
1da177e4
LT
190
191 snd_assert(spec->channel_mode, return -ENXIO);
fd2c326d
TI
192 for (i = 0; i < items; i++) {
193 if (spec->multiout.max_channels == spec->channel_mode[i].channels) {
194 ucontrol->value.enumerated.item[0] = i;
195 break;
196 }
197 }
1da177e4
LT
198 return 0;
199}
200
201static int alc880_ch_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
202{
203 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
204 struct alc_spec *spec = codec->spec;
205 int mode;
206
207 snd_assert(spec->channel_mode, return -ENXIO);
208 mode = ucontrol->value.enumerated.item[0] ? 1 : 0;
209 if (spec->multiout.max_channels == spec->channel_mode[mode].channels &&
210 ! codec->in_resume)
211 return 0;
212
213 /* change the current channel setting */
214 spec->multiout.max_channels = spec->channel_mode[mode].channels;
215 if (spec->channel_mode[mode].sequence)
216 snd_hda_sequence_write(codec, spec->channel_mode[mode].sequence);
217
218 return 1;
219}
220
221
41e41f1f
TI
222/*
223 * bound volume controls
224 *
225 * bind multiple volumes (# indices, from 0)
226 */
227
228#define AMP_VAL_IDX_SHIFT 19
229#define AMP_VAL_IDX_MASK (0x0f<<19)
230
05acb863 231static int alc_bind_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
41e41f1f
TI
232{
233 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
234 struct alc_spec *spec = codec->spec;
235 unsigned long pval;
236
237 down(&spec->bind_mutex);
238 pval = kcontrol->private_value;
239 kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */
05acb863 240 snd_hda_mixer_amp_switch_info(kcontrol, uinfo);
41e41f1f
TI
241 kcontrol->private_value = pval;
242 up(&spec->bind_mutex);
243 return 0;
244}
245
05acb863 246static int alc_bind_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
41e41f1f
TI
247{
248 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
249 struct alc_spec *spec = codec->spec;
250 unsigned long pval;
251
252 down(&spec->bind_mutex);
253 pval = kcontrol->private_value;
254 kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */
05acb863 255 snd_hda_mixer_amp_switch_get(kcontrol, ucontrol);
41e41f1f
TI
256 kcontrol->private_value = pval;
257 up(&spec->bind_mutex);
258 return 0;
259}
260
05acb863 261static int alc_bind_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
41e41f1f
TI
262{
263 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
264 struct alc_spec *spec = codec->spec;
265 unsigned long pval;
266 int i, indices, change = 0;
267
268 down(&spec->bind_mutex);
269 pval = kcontrol->private_value;
270 indices = (pval & AMP_VAL_IDX_MASK) >> AMP_VAL_IDX_SHIFT;
271 for (i = 0; i < indices; i++) {
272 kcontrol->private_value = (pval & ~AMP_VAL_IDX_MASK) | (i << AMP_VAL_IDX_SHIFT);
05acb863 273 change |= snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
41e41f1f
TI
274 }
275 kcontrol->private_value = pval;
276 up(&spec->bind_mutex);
277 return change;
278}
279
05acb863 280#define ALC_BIND_MUTE_MONO(xname, nid, channel, indices, direction) \
41e41f1f 281 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
05acb863
TI
282 .info = alc_bind_switch_info, \
283 .get = alc_bind_switch_get, \
284 .put = alc_bind_switch_put, \
41e41f1f
TI
285 .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, indices, direction) }
286
05acb863 287#define ALC_BIND_MUTE(xname,nid,indices,dir) ALC_BIND_MUTE_MONO(xname,nid,3,indices,dir)
41e41f1f 288
a9430dd8
JW
289/*
290 * Control of pin widget settings via the mixer. Only boolean settings are
291 * supported, so VrefEn can't be controlled using these functions as they
292 * stand.
293 */
294static int alc_pinctl_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
295{
296 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
297 uinfo->count = 1;
298 uinfo->value.integer.min = 0;
299 uinfo->value.integer.max = 1;
300 return 0;
301}
302
303static int alc_pinctl_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
304{
305 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
306 hda_nid_t nid = kcontrol->private_value & 0xffff;
307 long mask = (kcontrol->private_value >> 16) & 0xff;
308 long *valp = ucontrol->value.integer.value;
309
310 *valp = 0;
311 if (snd_hda_codec_read(codec,nid,0,AC_VERB_GET_PIN_WIDGET_CONTROL,0x00) & mask)
312 *valp = 1;
313 return 0;
314}
315
316static int alc_pinctl_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
317{
318 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
319 hda_nid_t nid = kcontrol->private_value & 0xffff;
320 long mask = (kcontrol->private_value >> 16) & 0xff;
321 long *valp = ucontrol->value.integer.value;
322 unsigned int pinctl = snd_hda_codec_read(codec,nid,0,AC_VERB_GET_PIN_WIDGET_CONTROL,0x00);
323 int change = ((pinctl & mask)!=0) != *valp;
324
325 if (change)
326 snd_hda_codec_write(codec,nid,0,AC_VERB_SET_PIN_WIDGET_CONTROL,
327 *valp?(pinctl|mask):(pinctl&~mask));
328 return change;
329}
330
331#define ALC_PINCTL_SWITCH(xname, nid, mask) \
332 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
333 .info = alc_pinctl_switch_info, \
334 .get = alc_pinctl_switch_get, \
335 .put = alc_pinctl_switch_put, \
336 .private_value = (nid) | (mask<<16) }
e9edcee0 337
1da177e4 338/*
e9edcee0
TI
339 * ALC880 3-stack model
340 *
341 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
342 * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18, F-Mic = 0x1b
343 * HP = 0x19
1da177e4
LT
344 */
345
e9edcee0
TI
346static hda_nid_t alc880_dac_nids[4] = {
347 /* front, rear, clfe, rear_surr */
348 0x02, 0x05, 0x04, 0x03
349};
350
351static hda_nid_t alc880_adc_nids[3] = {
352 /* ADC0-2 */
353 0x07, 0x08, 0x09,
354};
355
356/* The datasheet says the node 0x07 is connected from inputs,
357 * but it shows zero connection in the real implementation on some devices.
1da177e4 358 */
e9edcee0
TI
359static hda_nid_t alc880_adc_nids_alt[2] = {
360 /* ADC1-2 */
361 0x08, 0x09,
362};
363
364#define ALC880_DIGOUT_NID 0x06
365#define ALC880_DIGIN_NID 0x0a
366
367static struct hda_input_mux alc880_capture_source = {
368 .num_items = 4,
369 .items = {
370 { "Mic", 0x0 },
371 { "Front Mic", 0x3 },
372 { "Line", 0x2 },
373 { "CD", 0x4 },
374 },
375};
376
377/* channel source setting (2/6 channel selection for 3-stack) */
378/* 2ch mode */
379static struct hda_verb alc880_threestack_ch2_init[] = {
380 /* set line-in to input, mute it */
381 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
382 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
383 /* set mic-in to input vref 80%, mute it */
384 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
385 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
386 { } /* end */
387};
388
389/* 6ch mode */
390static struct hda_verb alc880_threestack_ch6_init[] = {
391 /* set line-in to output, unmute it */
392 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
393 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
394 /* set mic-in to output, unmute it */
395 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
396 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
397 { } /* end */
398};
399
400static struct alc_channel_mode alc880_threestack_modes[2] = {
401 { 2, alc880_threestack_ch2_init },
402 { 6, alc880_threestack_ch6_init },
403};
404
405static snd_kcontrol_new_t alc880_three_stack_mixer[] = {
05acb863
TI
406 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
407 ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
408 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
e9edcee0 409 ALC_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
05acb863
TI
410 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
411 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
412 ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
413 ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
1da177e4
LT
414 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
415 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
416 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
417 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
418 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
419 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
420 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
421 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
422 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
423 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
e9edcee0
TI
424 HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
425 {
426 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
427 .name = "Channel Mode",
428 .info = alc880_ch_mode_info,
429 .get = alc880_ch_mode_get,
430 .put = alc880_ch_mode_put,
431 },
432 { } /* end */
433};
434
435/* capture mixer elements */
436static snd_kcontrol_new_t alc880_capture_mixer[] = {
437 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
438 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
439 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
440 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
441 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
442 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
1da177e4
LT
443 {
444 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
445 /* The multiple "Capture Source" controls confuse alsamixer
446 * So call somewhat different..
447 * FIXME: the controls appear in the "playback" view!
448 */
449 /* .name = "Capture Source", */
450 .name = "Input Source",
e9edcee0 451 .count = 3,
1da177e4
LT
452 .info = alc_mux_enum_info,
453 .get = alc_mux_enum_get,
454 .put = alc_mux_enum_put,
455 },
1da177e4
LT
456 { } /* end */
457};
458
e9edcee0
TI
459/* capture mixer elements (in case NID 0x07 not available) */
460static snd_kcontrol_new_t alc880_capture_alt_mixer[] = {
71fe7b82
TI
461 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
462 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
463 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
464 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
1da177e4
LT
465 {
466 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
467 /* The multiple "Capture Source" controls confuse alsamixer
468 * So call somewhat different..
469 * FIXME: the controls appear in the "playback" view!
470 */
471 /* .name = "Capture Source", */
472 .name = "Input Source",
473 .count = 2,
474 .info = alc_mux_enum_info,
475 .get = alc_mux_enum_get,
476 .put = alc_mux_enum_put,
477 },
1da177e4
LT
478 { } /* end */
479};
480
e9edcee0
TI
481
482
483/*
484 * ALC880 5-stack model
485 *
486 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d), Side = 0x02 (0xd)
487 * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
488 * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
489 */
490
491/* additional mixers to alc880_three_stack_mixer */
492static snd_kcontrol_new_t alc880_five_stack_mixer[] = {
493 HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
494 ALC_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
1da177e4
LT
495 { } /* end */
496};
497
e9edcee0
TI
498/* channel source setting (6/8 channel selection for 5-stack) */
499/* 6ch mode */
500static struct hda_verb alc880_fivestack_ch6_init[] = {
501 /* set line-in to input, mute it */
502 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
503 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
dfc0ff62
TI
504 { } /* end */
505};
506
e9edcee0
TI
507/* 8ch mode */
508static struct hda_verb alc880_fivestack_ch8_init[] = {
509 /* set line-in to output, unmute it */
510 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
511 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
512 { } /* end */
513};
514
515static struct alc_channel_mode alc880_fivestack_modes[2] = {
516 { 6, alc880_fivestack_ch6_init },
517 { 8, alc880_fivestack_ch8_init },
518};
519
520
521/*
522 * ALC880 6-stack model
523 *
524 * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e), Side = 0x05 (0x0f)
525 * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
526 * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
527 */
528
529static hda_nid_t alc880_6st_dac_nids[4] = {
530 /* front, rear, clfe, rear_surr */
531 0x02, 0x03, 0x04, 0x05
532};
533
534static struct hda_input_mux alc880_6stack_capture_source = {
535 .num_items = 4,
536 .items = {
537 { "Mic", 0x0 },
538 { "Front Mic", 0x1 },
539 { "Line", 0x2 },
540 { "CD", 0x4 },
541 },
542};
543
544/* fixed 8-channels */
545static struct alc_channel_mode alc880_sixstack_modes[1] = {
546 { 8, NULL },
547};
548
16ded525
TI
549static snd_kcontrol_new_t alc880_six_stack_mixer[] = {
550 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
551 ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
552 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
553 ALC_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
554 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
555 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
556 ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
557 ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
558 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
559 ALC_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
560 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
561 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
562 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
563 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
564 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
565 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
566 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
567 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
568 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
569 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
16ded525
TI
570 {
571 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
572 .name = "Channel Mode",
573 .info = alc880_ch_mode_info,
574 .get = alc880_ch_mode_get,
575 .put = alc880_ch_mode_put,
576 },
577 { } /* end */
578};
579
e9edcee0
TI
580
581/*
582 * ALC880 W810 model
583 *
584 * W810 has rear IO for:
585 * Front (DAC 02)
586 * Surround (DAC 03)
587 * Center/LFE (DAC 04)
588 * Digital out (06)
589 *
590 * The system also has a pair of internal speakers, and a headphone jack.
591 * These are both connected to Line2 on the codec, hence to DAC 02.
592 *
593 * There is a variable resistor to control the speaker or headphone
594 * volume. This is a hardware-only device without a software API.
595 *
596 * Plugging headphones in will disable the internal speakers. This is
597 * implemented in hardware, not via the driver using jack sense. In
598 * a similar fashion, plugging into the rear socket marked "front" will
599 * disable both the speakers and headphones.
600 *
601 * For input, there's a microphone jack, and an "audio in" jack.
602 * These may not do anything useful with this driver yet, because I
603 * haven't setup any initialization verbs for these yet...
604 */
605
606static hda_nid_t alc880_w810_dac_nids[3] = {
607 /* front, rear/surround, clfe */
608 0x02, 0x03, 0x04
16ded525
TI
609};
610
e9edcee0
TI
611/* fixed 6 channels */
612static struct alc_channel_mode alc880_w810_modes[1] = {
613 { 6, NULL }
614};
615
616/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
617static snd_kcontrol_new_t alc880_w810_base_mixer[] = {
16ded525
TI
618 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
619 ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
620 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
621 ALC_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
622 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
623 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
624 ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
625 ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
e9edcee0
TI
626 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
627 { } /* end */
628};
629
630
631/*
632 * Z710V model
633 *
634 * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
635 * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?), Line = 0x1a
636 */
637
638static hda_nid_t alc880_z71v_dac_nids[1] = {
639 0x02
640};
641#define ALC880_Z71V_HP_DAC 0x03
642
643/* fixed 2 channels */
644static struct alc_channel_mode alc880_2_jack_modes[1] = {
645 { 2, NULL }
646};
647
648static snd_kcontrol_new_t alc880_z71v_mixer[] = {
649 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
650 ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
651 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
652 ALC_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
16ded525
TI
653 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
654 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16ded525
TI
655 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
656 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16ded525
TI
657 { } /* end */
658};
659
e9edcee0
TI
660
661/* FIXME! */
662/*
663 * ALC880 F1734 model
664 *
665 * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
666 * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
667 */
668
669static hda_nid_t alc880_f1734_dac_nids[1] = {
670 0x03
671};
672#define ALC880_F1734_HP_DAC 0x02
673
674static snd_kcontrol_new_t alc880_f1734_mixer[] = {
675 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
676 ALC_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
677 HDA_CODEC_VOLUME("Internal Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
678 ALC_BIND_MUTE("Internal Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
679 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
680 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
681 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
682 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
683 { } /* end */
684};
685
686
687/* FIXME! */
688/*
689 * ALC880 ASUS model
690 *
691 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
692 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
693 * Mic = 0x18, Line = 0x1a
694 */
695
696#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */
697#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */
698
699static snd_kcontrol_new_t alc880_asus_mixer[] = {
16ded525
TI
700 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
701 ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
702 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
703 ALC_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
704 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
705 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
706 ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
707 ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
708 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
709 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
710 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
711 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16ded525
TI
712 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
713 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16ded525
TI
714 {
715 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
716 .name = "Channel Mode",
717 .info = alc880_ch_mode_info,
718 .get = alc880_ch_mode_get,
719 .put = alc880_ch_mode_put,
720 },
721 { } /* end */
722};
e9edcee0
TI
723
724/* FIXME! */
725/*
726 * ALC880 ASUS W1V model
727 *
728 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
729 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
730 * Mic = 0x18, Line = 0x1a, Line2 = 0x1b
731 */
732
733/* additional mixers to alc880_asus_mixer */
734static snd_kcontrol_new_t alc880_asus_w1v_mixer[] = {
735 HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
736 HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
737 { } /* end */
738};
739
3c10a9d9
TI
740/* additional mixers to alc880_asus_mixer */
741static snd_kcontrol_new_t alc880_pcbeep_mixer[] = {
742 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
743 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
744 { } /* end */
745};
e9edcee0 746
1da177e4 747/*
e9edcee0 748 * build control elements
1da177e4
LT
749 */
750static int alc_build_controls(struct hda_codec *codec)
751{
752 struct alc_spec *spec = codec->spec;
753 int err;
754 int i;
755
756 for (i = 0; i < spec->num_mixers; i++) {
757 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
758 if (err < 0)
759 return err;
760 }
761
762 if (spec->multiout.dig_out_nid) {
763 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
764 if (err < 0)
765 return err;
766 }
767 if (spec->dig_in_nid) {
768 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
769 if (err < 0)
770 return err;
771 }
772 return 0;
773}
774
e9edcee0 775
1da177e4
LT
776/*
777 * initialize the codec volumes, etc
778 */
779
e9edcee0
TI
780/*
781 * generic initialization of ADC, input mixers and output mixers
782 */
783static struct hda_verb alc880_volume_init_verbs[] = {
784 /*
785 * Unmute ADC0-2 and set the default input to mic-in
786 */
71fe7b82 787 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
e9edcee0 788 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
71fe7b82 789 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
e9edcee0 790 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
71fe7b82 791 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
e9edcee0 792 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1da177e4 793
e9edcee0
TI
794 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
795 * mixer widget
1da177e4
LT
796 * Note: PASD motherboards uses the Line In 2 as the input for front panel
797 * mic (mic 2)
798 */
e9edcee0 799 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
16ded525 800 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
e9edcee0
TI
801 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
802 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
803 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
804 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
1da177e4 805
e9edcee0
TI
806 /*
807 * Set up output mixers (0x0c - 0x0f)
1da177e4 808 */
e9edcee0
TI
809 /* set vol=0 to output mixers */
810 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
811 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
812 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
813 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
814 /* set up input amps for analog loopback */
815 /* Amp Indices: DAC = 0, mixer = 1 */
05acb863
TI
816 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
817 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
05acb863
TI
818 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
819 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
05acb863
TI
820 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
821 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
05acb863
TI
822 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
823 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1da177e4
LT
824
825 { }
826};
827
e9edcee0
TI
828/*
829 * 3-stack pin configuration:
830 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
831 */
832static struct hda_verb alc880_pin_3stack_init_verbs[] = {
833 /*
834 * preset connection lists of input pins
835 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
836 */
837 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
838 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
839 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
840
841 /*
842 * Set pin mode and muting
843 */
844 /* set front pin widgets 0x14 for output */
05acb863 845 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
e9edcee0
TI
846 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
847 /* Mic1 (rear panel) pin widget for input and vref at 80% */
848 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
849 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
850 /* Mic2 (as headphone out) for HP output */
851 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
852 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1da177e4 853 /* Line In pin widget for input */
05acb863 854 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
e9edcee0
TI
855 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
856 /* Line2 (as front mic) pin widget for input and vref at 80% */
857 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
858 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1da177e4 859 /* CD pin widget for input */
05acb863 860 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1da177e4 861
e9edcee0
TI
862 { }
863};
1da177e4 864
e9edcee0
TI
865/*
866 * 5-stack pin configuration:
867 * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
868 * line-in/side = 0x1a, f-mic = 0x1b
869 */
870static struct hda_verb alc880_pin_5stack_init_verbs[] = {
871 /*
872 * preset connection lists of input pins
873 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
1da177e4 874 */
e9edcee0
TI
875 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
876 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
1da177e4 877
e9edcee0
TI
878 /*
879 * Set pin mode and muting
1da177e4 880 */
e9edcee0
TI
881 /* set pin widgets 0x14-0x17 for output */
882 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
883 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
884 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
885 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
886 /* unmute pins for output (no gain on this amp) */
887 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
888 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
889 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
890 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
891
892 /* Mic1 (rear panel) pin widget for input and vref at 80% */
893 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
894 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
895 /* Mic2 (as headphone out) for HP output */
896 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
897 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
898 /* Line In pin widget for input */
899 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
900 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
901 /* Line2 (as front mic) pin widget for input and vref at 80% */
902 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
903 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
904 /* CD pin widget for input */
905 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1da177e4
LT
906
907 { }
908};
909
e9edcee0
TI
910/*
911 * W810 pin configuration:
912 * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
913 */
914static struct hda_verb alc880_pin_w810_init_verbs[] = {
915 /* hphone/speaker input selector: front DAC */
916 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
1da177e4 917
05acb863 918 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
e9edcee0 919 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
05acb863 920 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
e9edcee0 921 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
05acb863 922 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
e9edcee0 923 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1da177e4 924
e9edcee0 925 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
05acb863 926 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1da177e4 927
1da177e4
LT
928 { }
929};
930
e9edcee0
TI
931/*
932 * Z71V pin configuration:
933 * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
934 */
935static struct hda_verb alc880_pin_z71v_init_verbs[] = {
05acb863 936 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
e9edcee0 937 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
05acb863 938 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
e9edcee0 939 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
dfc0ff62 940
16ded525 941 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
e9edcee0 942 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16ded525 943 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
e9edcee0 944 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16ded525
TI
945
946 { }
947};
948
e9edcee0
TI
949/*
950 * 6-stack pin configuration:
951 * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18, f-mic = 0x19,
952 * line = 0x1a, HP = 0x1b
953 */
954static struct hda_verb alc880_pin_6stack_init_verbs[] = {
955 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
956
16ded525 957 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
e9edcee0 958 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16ded525 959 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
e9edcee0 960 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16ded525 961 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
e9edcee0 962 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16ded525 963 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
e9edcee0
TI
964 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
965
16ded525 966 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
e9edcee0 967 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16ded525 968 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
e9edcee0 969 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16ded525 970 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
e9edcee0 971 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16ded525 972 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
e9edcee0 973 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16ded525
TI
974 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
975
e9edcee0
TI
976 { }
977};
978
979/* FIXME! */
980/*
981 * F1734 pin configuration:
982 * HP = 0x14, speaker-out = 0x15, mic = 0x18
983 */
984static struct hda_verb alc880_pin_f1734_init_verbs[] = {
16ded525
TI
985 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
986 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
987 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
988 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
989
e9edcee0 990 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16ded525 991 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
e9edcee0 992 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16ded525 993 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16ded525 994
e9edcee0
TI
995 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
996 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16ded525 997 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
e9edcee0 998 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16ded525 999 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
e9edcee0 1000 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16ded525 1001 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
e9edcee0 1002 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16ded525 1003 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
dfc0ff62
TI
1004
1005 { }
1006};
1007
e9edcee0
TI
1008/* FIXME! */
1009/*
1010 * ASUS pin configuration:
1011 * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
1012 */
1013static struct hda_verb alc880_pin_asus_init_verbs[] = {
16ded525
TI
1014 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
1015 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
1016 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
1017 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
1018
1019 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
e9edcee0 1020 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16ded525 1021 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
e9edcee0 1022 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16ded525 1023 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
e9edcee0 1024 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16ded525 1025 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
e9edcee0
TI
1026 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1027
1028 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1029 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1030 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1031 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1032 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1033 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16ded525 1034 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
e9edcee0 1035 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16ded525
TI
1036 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1037
e9edcee0
TI
1038 { }
1039};
16ded525 1040
e9edcee0
TI
1041/* Enable GPIO mask and set output */
1042static struct hda_verb alc880_gpio1_init_verbs[] = {
1043 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
1044 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
1045 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
1046};
16ded525 1047
e9edcee0
TI
1048/* Enable GPIO mask and set output */
1049static struct hda_verb alc880_gpio2_init_verbs[] = {
1050 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
1051 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
1052 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
16ded525
TI
1053};
1054
1055
e9edcee0
TI
1056/*
1057 */
1058
1da177e4
LT
1059static int alc_init(struct hda_codec *codec)
1060{
1061 struct alc_spec *spec = codec->spec;
e9edcee0
TI
1062 unsigned int i;
1063
1064 for (i = 0; i < spec->num_init_verbs; i++)
1065 snd_hda_sequence_write(codec, spec->init_verbs[i]);
1da177e4
LT
1066 return 0;
1067}
1068
1069#ifdef CONFIG_PM
1070/*
1071 * resume
1072 */
1073static int alc_resume(struct hda_codec *codec)
1074{
1075 struct alc_spec *spec = codec->spec;
1076 int i;
1077
1078 alc_init(codec);
e9edcee0 1079 for (i = 0; i < spec->num_mixers; i++)
1da177e4 1080 snd_hda_resume_ctls(codec, spec->mixers[i]);
1da177e4
LT
1081 if (spec->multiout.dig_out_nid)
1082 snd_hda_resume_spdif_out(codec);
1083 if (spec->dig_in_nid)
1084 snd_hda_resume_spdif_in(codec);
1085
1086 return 0;
1087}
1088#endif
1089
1090/*
1091 * Analog playback callbacks
1092 */
1093static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
1094 struct hda_codec *codec,
1095 snd_pcm_substream_t *substream)
1096{
1097 struct alc_spec *spec = codec->spec;
1098 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
1099}
1100
1101static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1102 struct hda_codec *codec,
1103 unsigned int stream_tag,
1104 unsigned int format,
1105 snd_pcm_substream_t *substream)
1106{
1107 struct alc_spec *spec = codec->spec;
1108 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag,
1109 format, substream);
1110}
1111
1112static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
1113 struct hda_codec *codec,
1114 snd_pcm_substream_t *substream)
1115{
1116 struct alc_spec *spec = codec->spec;
1117 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
1118}
1119
1120/*
1121 * Digital out
1122 */
1123static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
1124 struct hda_codec *codec,
1125 snd_pcm_substream_t *substream)
1126{
1127 struct alc_spec *spec = codec->spec;
1128 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
1129}
1130
1131static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
1132 struct hda_codec *codec,
1133 snd_pcm_substream_t *substream)
1134{
1135 struct alc_spec *spec = codec->spec;
1136 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
1137}
1138
1139/*
1140 * Analog capture
1141 */
1142static int alc880_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
1143 struct hda_codec *codec,
1144 unsigned int stream_tag,
1145 unsigned int format,
1146 snd_pcm_substream_t *substream)
1147{
1148 struct alc_spec *spec = codec->spec;
1149
1150 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
1151 stream_tag, 0, format);
1152 return 0;
1153}
1154
1155static int alc880_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
1156 struct hda_codec *codec,
1157 snd_pcm_substream_t *substream)
1158{
1159 struct alc_spec *spec = codec->spec;
1160
1161 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0);
1162 return 0;
1163}
1164
1165
1166/*
1167 */
1168static struct hda_pcm_stream alc880_pcm_analog_playback = {
1169 .substreams = 1,
1170 .channels_min = 2,
1171 .channels_max = 8,
e9edcee0 1172 /* NID is set in alc_build_pcms */
1da177e4
LT
1173 .ops = {
1174 .open = alc880_playback_pcm_open,
1175 .prepare = alc880_playback_pcm_prepare,
1176 .cleanup = alc880_playback_pcm_cleanup
1177 },
1178};
1179
1180static struct hda_pcm_stream alc880_pcm_analog_capture = {
1181 .substreams = 2,
1182 .channels_min = 2,
1183 .channels_max = 2,
e9edcee0 1184 /* NID is set in alc_build_pcms */
1da177e4
LT
1185 .ops = {
1186 .prepare = alc880_capture_pcm_prepare,
1187 .cleanup = alc880_capture_pcm_cleanup
1188 },
1189};
1190
1191static struct hda_pcm_stream alc880_pcm_digital_playback = {
1192 .substreams = 1,
1193 .channels_min = 2,
1194 .channels_max = 2,
1195 /* NID is set in alc_build_pcms */
1196 .ops = {
1197 .open = alc880_dig_playback_pcm_open,
1198 .close = alc880_dig_playback_pcm_close
1199 },
1200};
1201
1202static struct hda_pcm_stream alc880_pcm_digital_capture = {
1203 .substreams = 1,
1204 .channels_min = 2,
1205 .channels_max = 2,
1206 /* NID is set in alc_build_pcms */
1207};
1208
1209static int alc_build_pcms(struct hda_codec *codec)
1210{
1211 struct alc_spec *spec = codec->spec;
1212 struct hda_pcm *info = spec->pcm_rec;
1213 int i;
1214
1215 codec->num_pcms = 1;
1216 codec->pcm_info = info;
1217
1218 info->name = spec->stream_name_analog;
1219 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
e9edcee0 1220 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
1da177e4 1221 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
e9edcee0 1222 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
1da177e4
LT
1223
1224 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
1225 for (i = 0; i < spec->num_channel_mode; i++) {
1226 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
1227 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
1228 }
1229 }
1230
1231 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
1232 codec->num_pcms++;
1233 info++;
1234 info->name = spec->stream_name_digital;
1235 if (spec->multiout.dig_out_nid) {
1236 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
1237 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
1238 }
1239 if (spec->dig_in_nid) {
1240 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
1241 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
1242 }
1243 }
1244
1245 return 0;
1246}
1247
1248static void alc_free(struct hda_codec *codec)
1249{
e9edcee0
TI
1250 struct alc_spec *spec = codec->spec;
1251 unsigned int i;
1252
1253 if (! spec)
1254 return;
1255
1256 if (spec->kctl_alloc) {
1257 for (i = 0; i < spec->num_kctl_used; i++)
1258 kfree(spec->kctl_alloc[i].name);
1259 kfree(spec->kctl_alloc);
1260 }
1261 kfree(spec);
1da177e4
LT
1262}
1263
1264/*
1265 */
1266static struct hda_codec_ops alc_patch_ops = {
1267 .build_controls = alc_build_controls,
1268 .build_pcms = alc_build_pcms,
1269 .init = alc_init,
1270 .free = alc_free,
1271#ifdef CONFIG_PM
1272 .resume = alc_resume,
1273#endif
1274};
1275
2fa522be
TI
1276
1277/*
1278 * Test configuration for debugging
1279 *
1280 * Almost all inputs/outputs are enabled. I/O pins can be configured via
1281 * enum controls.
1282 */
1283#ifdef CONFIG_SND_DEBUG
1284static hda_nid_t alc880_test_dac_nids[4] = {
1285 0x02, 0x03, 0x04, 0x05
1286};
1287
1288static struct hda_input_mux alc880_test_capture_source = {
1289 .num_items = 5,
1290 .items = {
1291 { "In-1", 0x0 },
1292 { "In-2", 0x1 },
1293 { "In-3", 0x2 },
1294 { "In-4", 0x3 },
1295 { "CD", 0x4 },
1296 },
1297};
1298
fd2c326d 1299static struct alc_channel_mode alc880_test_modes[4] = {
2fa522be 1300 { 2, NULL },
fd2c326d 1301 { 4, NULL },
2fa522be 1302 { 6, NULL },
fd2c326d 1303 { 8, NULL },
2fa522be
TI
1304};
1305
1306static int alc_test_pin_ctl_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
1307{
1308 static char *texts[] = {
1309 "N/A", "Line Out", "HP Out",
1310 "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
1311 };
1312 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1313 uinfo->count = 1;
1314 uinfo->value.enumerated.items = 8;
1315 if (uinfo->value.enumerated.item >= 8)
1316 uinfo->value.enumerated.item = 7;
1317 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1318 return 0;
1319}
1320
1321static int alc_test_pin_ctl_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
1322{
1323 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1324 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
1325 unsigned int pin_ctl, item = 0;
1326
1327 pin_ctl = snd_hda_codec_read(codec, nid, 0,
1328 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
1329 if (pin_ctl & AC_PINCTL_OUT_EN) {
1330 if (pin_ctl & AC_PINCTL_HP_EN)
1331 item = 2;
1332 else
1333 item = 1;
1334 } else if (pin_ctl & AC_PINCTL_IN_EN) {
1335 switch (pin_ctl & AC_PINCTL_VREFEN) {
1336 case AC_PINCTL_VREF_HIZ: item = 3; break;
1337 case AC_PINCTL_VREF_50: item = 4; break;
1338 case AC_PINCTL_VREF_GRD: item = 5; break;
1339 case AC_PINCTL_VREF_80: item = 6; break;
1340 case AC_PINCTL_VREF_100: item = 7; break;
1341 }
1342 }
1343 ucontrol->value.enumerated.item[0] = item;
1344 return 0;
1345}
1346
1347static int alc_test_pin_ctl_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
1348{
1349 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1350 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
1351 static unsigned int ctls[] = {
1352 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
1353 AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
1354 AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
1355 AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
1356 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
1357 AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
1358 };
1359 unsigned int old_ctl, new_ctl;
1360
1361 old_ctl = snd_hda_codec_read(codec, nid, 0,
1362 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
1363 new_ctl = ctls[ucontrol->value.enumerated.item[0]];
1364 if (old_ctl != new_ctl) {
1365 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, new_ctl);
1366 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
1367 ucontrol->value.enumerated.item[0] >= 3 ? 0xb080 : 0xb000);
1368 return 1;
1369 }
1370 return 0;
1371}
1372
1373static int alc_test_pin_src_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
1374{
1375 static char *texts[] = {
1376 "Front", "Surround", "CLFE", "Side"
1377 };
1378 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1379 uinfo->count = 1;
1380 uinfo->value.enumerated.items = 4;
1381 if (uinfo->value.enumerated.item >= 4)
1382 uinfo->value.enumerated.item = 3;
1383 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1384 return 0;
1385}
1386
1387static int alc_test_pin_src_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
1388{
1389 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1390 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
1391 unsigned int sel;
1392
1393 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
1394 ucontrol->value.enumerated.item[0] = sel & 3;
1395 return 0;
1396}
1397
1398static int alc_test_pin_src_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
1399{
1400 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1401 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
1402 unsigned int sel;
1403
1404 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
1405 if (ucontrol->value.enumerated.item[0] != sel) {
1406 sel = ucontrol->value.enumerated.item[0] & 3;
1407 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, sel);
1408 return 1;
1409 }
1410 return 0;
1411}
1412
1413#define PIN_CTL_TEST(xname,nid) { \
1414 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1415 .name = xname, \
1416 .info = alc_test_pin_ctl_info, \
1417 .get = alc_test_pin_ctl_get, \
1418 .put = alc_test_pin_ctl_put, \
1419 .private_value = nid \
1420 }
1421
1422#define PIN_SRC_TEST(xname,nid) { \
1423 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1424 .name = xname, \
1425 .info = alc_test_pin_src_info, \
1426 .get = alc_test_pin_src_get, \
1427 .put = alc_test_pin_src_put, \
1428 .private_value = nid \
1429 }
1430
1431static snd_kcontrol_new_t alc880_test_mixer[] = {
05acb863
TI
1432 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1433 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1434 HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
1435 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
1436 ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
1437 ALC_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
1c1fa8b6
JL
1438 ALC_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
1439 ALC_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
2fa522be
TI
1440 PIN_CTL_TEST("Front Pin Mode", 0x14),
1441 PIN_CTL_TEST("Surround Pin Mode", 0x15),
1442 PIN_CTL_TEST("CLFE Pin Mode", 0x16),
1443 PIN_CTL_TEST("Side Pin Mode", 0x17),
1444 PIN_CTL_TEST("In-1 Pin Mode", 0x18),
1445 PIN_CTL_TEST("In-2 Pin Mode", 0x19),
1446 PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
1447 PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
1448 PIN_SRC_TEST("In-1 Pin Source", 0x18),
1449 PIN_SRC_TEST("In-2 Pin Source", 0x19),
1450 PIN_SRC_TEST("In-3 Pin Source", 0x1a),
1451 PIN_SRC_TEST("In-4 Pin Source", 0x1b),
1452 HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
1453 HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
1454 HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
1455 HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
1456 HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
1457 HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
1458 HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
1459 HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
1460 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
1461 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
2fa522be
TI
1462 {
1463 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1464 .name = "Channel Mode",
1465 .info = alc880_ch_mode_info,
1466 .get = alc880_ch_mode_get,
1467 .put = alc880_ch_mode_put,
1468 },
1469 { } /* end */
1470};
1471
1472static struct hda_verb alc880_test_init_verbs[] = {
1473 /* Unmute inputs of 0x0c - 0x0f */
05acb863
TI
1474 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1475 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1476 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1477 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1478 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1479 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1480 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1481 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2fa522be 1482 /* Vol output for 0x0c-0x0f */
05acb863
TI
1483 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1484 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1485 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1486 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2fa522be 1487 /* Set output pins 0x14-0x17 */
05acb863
TI
1488 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1489 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1490 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1491 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2fa522be 1492 /* Unmute output pins 0x14-0x17 */
05acb863
TI
1493 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1494 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1495 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1496 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2fa522be 1497 /* Set input pins 0x18-0x1c */
16ded525
TI
1498 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1499 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
05acb863
TI
1500 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1501 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1502 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2fa522be 1503 /* Mute input pins 0x18-0x1b */
05acb863
TI
1504 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1505 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1506 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1507 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
71fe7b82 1508 /* ADC set up */
05acb863 1509 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
71fe7b82 1510 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
05acb863 1511 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
71fe7b82 1512 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
05acb863 1513 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
71fe7b82 1514 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
05acb863
TI
1515 /* Analog input/passthru */
1516 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1517 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1518 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
1519 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
1520 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2fa522be
TI
1521 { }
1522};
1523#endif
1524
1da177e4
LT
1525/*
1526 */
1527
1528static struct hda_board_config alc880_cfg_tbl[] = {
1529 /* Back 3 jack, front 2 jack */
1530 { .modelname = "3stack", .config = ALC880_3ST },
7291548d
TI
1531 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe200, .config = ALC880_3ST },
1532 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe201, .config = ALC880_3ST },
1533 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe202, .config = ALC880_3ST },
1534 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe203, .config = ALC880_3ST },
1535 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe204, .config = ALC880_3ST },
1536 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe205, .config = ALC880_3ST },
1537 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe206, .config = ALC880_3ST },
1538 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe207, .config = ALC880_3ST },
1539 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe208, .config = ALC880_3ST },
1540 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe209, .config = ALC880_3ST },
1541 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20a, .config = ALC880_3ST },
1542 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20b, .config = ALC880_3ST },
1543 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20c, .config = ALC880_3ST },
1544 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20d, .config = ALC880_3ST },
1545 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20e, .config = ALC880_3ST },
1546 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20f, .config = ALC880_3ST },
1547 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe210, .config = ALC880_3ST },
1548 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe211, .config = ALC880_3ST },
1549 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe214, .config = ALC880_3ST },
1550 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe302, .config = ALC880_3ST },
1551 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe303, .config = ALC880_3ST },
1552 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe304, .config = ALC880_3ST },
1553 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe306, .config = ALC880_3ST },
1554 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe307, .config = ALC880_3ST },
1555 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe404, .config = ALC880_3ST },
1556 { .pci_subvendor = 0x8086, .pci_subdevice = 0xa101, .config = ALC880_3ST },
1557 { .pci_subvendor = 0x107b, .pci_subdevice = 0x3031, .config = ALC880_3ST },
1558 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4036, .config = ALC880_3ST },
1559 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4037, .config = ALC880_3ST },
1560 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4038, .config = ALC880_3ST },
1561 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4040, .config = ALC880_3ST },
1562 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4041, .config = ALC880_3ST },
1da177e4
LT
1563
1564 /* Back 3 jack, front 2 jack (Internal add Aux-In) */
7291548d 1565 { .pci_subvendor = 0x1025, .pci_subdevice = 0xe310, .config = ALC880_3ST },
16ded525 1566 { .pci_subvendor = 0x104d, .pci_subdevice = 0x81d6, .config = ALC880_3ST },
0ca21611 1567 { .pci_subvendor = 0x104d, .pci_subdevice = 0x81a0, .config = ALC880_3ST },
1da177e4
LT
1568
1569 /* Back 3 jack plus 1 SPDIF out jack, front 2 jack */
1570 { .modelname = "3stack-digout", .config = ALC880_3ST_DIG },
7291548d 1571 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe308, .config = ALC880_3ST_DIG },
5a47fe3c 1572 { .pci_subvendor = 0x1025, .pci_subdevice = 0x0070, .config = ALC880_3ST_DIG },
1da177e4
LT
1573
1574 /* Back 3 jack plus 1 SPDIF out jack, front 2 jack (Internal add Aux-In)*/
7291548d
TI
1575 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe305, .config = ALC880_3ST_DIG },
1576 { .pci_subvendor = 0x8086, .pci_subdevice = 0xd402, .config = ALC880_3ST_DIG },
1577 { .pci_subvendor = 0x1025, .pci_subdevice = 0xe309, .config = ALC880_3ST_DIG },
1da177e4
LT
1578
1579 /* Back 5 jack, front 2 jack */
1580 { .modelname = "5stack", .config = ALC880_5ST },
7291548d
TI
1581 { .pci_subvendor = 0x107b, .pci_subdevice = 0x3033, .config = ALC880_5ST },
1582 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4039, .config = ALC880_5ST },
1583 { .pci_subvendor = 0x107b, .pci_subdevice = 0x3032, .config = ALC880_5ST },
1584 { .pci_subvendor = 0x103c, .pci_subdevice = 0x2a09, .config = ALC880_5ST },
16ded525 1585 { .pci_subvendor = 0x1043, .pci_subdevice = 0x814e, .config = ALC880_5ST },
1da177e4
LT
1586
1587 /* Back 5 jack plus 1 SPDIF out jack, front 2 jack */
1588 { .modelname = "5stack-digout", .config = ALC880_5ST_DIG },
7291548d
TI
1589 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe224, .config = ALC880_5ST_DIG },
1590 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe400, .config = ALC880_5ST_DIG },
1591 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe401, .config = ALC880_5ST_DIG },
1592 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe402, .config = ALC880_5ST_DIG },
1593 { .pci_subvendor = 0x8086, .pci_subdevice = 0xd400, .config = ALC880_5ST_DIG },
1594 { .pci_subvendor = 0x8086, .pci_subdevice = 0xd401, .config = ALC880_5ST_DIG },
1595 { .pci_subvendor = 0x8086, .pci_subdevice = 0xa100, .config = ALC880_5ST_DIG },
1596 { .pci_subvendor = 0x1565, .pci_subdevice = 0x8202, .config = ALC880_5ST_DIG },
16ded525 1597 { .pci_subvendor = 0x1019, .pci_subdevice = 0xa880, .config = ALC880_5ST_DIG },
7a318a70 1598 /* { .pci_subvendor = 0x1019, .pci_subdevice = 0xa884, .config = ALC880_5ST_DIG }, */ /* conflict with 6stack */
16ded525 1599 { .pci_subvendor = 0x1695, .pci_subdevice = 0x400d, .config = ALC880_5ST_DIG },
b0af0de5
TI
1600 /* note subvendor = 0 below */
1601 /* { .pci_subvendor = 0x0000, .pci_subdevice = 0x8086, .config = ALC880_5ST_DIG }, */
1da177e4
LT
1602
1603 { .modelname = "w810", .config = ALC880_W810 },
7291548d 1604 { .pci_subvendor = 0x161f, .pci_subdevice = 0x203d, .config = ALC880_W810 },
1da177e4 1605
dfc0ff62 1606 { .modelname = "z71v", .config = ALC880_Z71V },
7291548d 1607 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_Z71V },
dfc0ff62 1608
b6482d48 1609 { .modelname = "6stack", .config = ALC880_6ST },
7a318a70 1610 { .pci_subvendor = 0x1019, .pci_subdevice = 0xa884, .config = ALC880_6ST }, /* Acer APFV */
b6482d48
TI
1611
1612 { .modelname = "6stack-digout", .config = ALC880_6ST_DIG },
16ded525
TI
1613 { .pci_subvendor = 0x2668, .pci_subdevice = 0x8086, .config = ALC880_6ST_DIG },
1614 { .pci_subvendor = 0x8086, .pci_subdevice = 0x2668, .config = ALC880_6ST_DIG },
1615 { .pci_subvendor = 0x1462, .pci_subdevice = 0x1150, .config = ALC880_6ST_DIG },
1616 { .pci_subvendor = 0xe803, .pci_subdevice = 0x1019, .config = ALC880_6ST_DIG },
1617
e9edcee0 1618 { .modelname = "asus", .config = ALC880_ASUS },
16ded525
TI
1619 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_ASUS_DIG },
1620 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1973, .config = ALC880_ASUS_DIG },
1621 { .pci_subvendor = 0x1043, .pci_subdevice = 0x19b3, .config = ALC880_ASUS_DIG },
1622 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1113, .config = ALC880_ASUS_DIG },
8648811f 1623 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1173, .config = ALC880_ASUS_DIG },
16ded525
TI
1624 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1993, .config = ALC880_ASUS },
1625 { .pci_subvendor = 0x1043, .pci_subdevice = 0x10c3, .config = ALC880_ASUS_DIG },
1626 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1133, .config = ALC880_ASUS },
1627 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1123, .config = ALC880_ASUS_DIG },
1628 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1143, .config = ALC880_ASUS },
1629 { .pci_subvendor = 0x1043, .pci_subdevice = 0x10b3, .config = ALC880_ASUS_W1V },
1630
1631 { .modelname = "uniwill", .config = ALC880_UNIWILL_DIG },
1632 { .pci_subvendor = 0x1584, .pci_subdevice = 0x9050, .config = ALC880_UNIWILL_DIG },
1633
1634 { .modelname = "F1734", .config = ALC880_F1734 },
1635 { .pci_subvendor = 0x1734, .pci_subdevice = 0x107c, .config = ALC880_F1734 },
1636
2fa522be
TI
1637#ifdef CONFIG_SND_DEBUG
1638 { .modelname = "test", .config = ALC880_TEST },
1639#endif
1640
1da177e4
LT
1641 {}
1642};
1643
16ded525
TI
1644/*
1645 * configuration template - to be copied to the spec instance
1646 */
1647struct alc_config_preset {
e9edcee0
TI
1648 snd_kcontrol_new_t *mixers[4];
1649 const struct hda_verb *init_verbs[4];
16ded525
TI
1650 unsigned int num_dacs;
1651 hda_nid_t *dac_nids;
1652 hda_nid_t dig_out_nid; /* optional */
1653 hda_nid_t hp_nid; /* optional */
1654 unsigned int num_adc_nids;
1655 hda_nid_t *adc_nids;
1656 unsigned int num_channel_mode;
1657 const struct alc_channel_mode *channel_mode;
1658 const struct hda_input_mux *input_mux;
1659};
1660
1661static struct alc_config_preset alc880_presets[] = {
1662 [ALC880_3ST] = {
e9edcee0
TI
1663 .mixers = { alc880_three_stack_mixer },
1664 .init_verbs = { alc880_volume_init_verbs, alc880_pin_3stack_init_verbs },
16ded525 1665 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
16ded525 1666 .dac_nids = alc880_dac_nids,
16ded525
TI
1667 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
1668 .channel_mode = alc880_threestack_modes,
1669 .input_mux = &alc880_capture_source,
1670 },
1671 [ALC880_3ST_DIG] = {
e9edcee0
TI
1672 .mixers = { alc880_three_stack_mixer },
1673 .init_verbs = { alc880_volume_init_verbs, alc880_pin_3stack_init_verbs },
16ded525 1674 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
16ded525
TI
1675 .dac_nids = alc880_dac_nids,
1676 .dig_out_nid = ALC880_DIGOUT_NID,
16ded525
TI
1677 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
1678 .channel_mode = alc880_threestack_modes,
1679 .input_mux = &alc880_capture_source,
1680 },
1681 [ALC880_5ST] = {
e9edcee0
TI
1682 .mixers = { alc880_three_stack_mixer, alc880_five_stack_mixer},
1683 .init_verbs = { alc880_volume_init_verbs, alc880_pin_5stack_init_verbs },
16ded525
TI
1684 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
1685 .dac_nids = alc880_dac_nids,
16ded525
TI
1686 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
1687 .channel_mode = alc880_fivestack_modes,
1688 .input_mux = &alc880_capture_source,
1689 },
1690 [ALC880_5ST_DIG] = {
e9edcee0
TI
1691 .mixers = { alc880_three_stack_mixer, alc880_five_stack_mixer },
1692 .init_verbs = { alc880_volume_init_verbs, alc880_pin_5stack_init_verbs },
16ded525
TI
1693 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
1694 .dac_nids = alc880_dac_nids,
1695 .dig_out_nid = ALC880_DIGOUT_NID,
16ded525
TI
1696 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
1697 .channel_mode = alc880_fivestack_modes,
1698 .input_mux = &alc880_capture_source,
1699 },
b6482d48
TI
1700 [ALC880_6ST] = {
1701 .mixers = { alc880_six_stack_mixer },
1702 .init_verbs = { alc880_volume_init_verbs, alc880_pin_6stack_init_verbs },
1703 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
1704 .dac_nids = alc880_6st_dac_nids,
1705 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
1706 .channel_mode = alc880_sixstack_modes,
1707 .input_mux = &alc880_6stack_capture_source,
1708 },
16ded525 1709 [ALC880_6ST_DIG] = {
e9edcee0
TI
1710 .mixers = { alc880_six_stack_mixer },
1711 .init_verbs = { alc880_volume_init_verbs, alc880_pin_6stack_init_verbs },
16ded525
TI
1712 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
1713 .dac_nids = alc880_6st_dac_nids,
1714 .dig_out_nid = ALC880_DIGOUT_NID,
16ded525
TI
1715 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
1716 .channel_mode = alc880_sixstack_modes,
1717 .input_mux = &alc880_6stack_capture_source,
1718 },
1719 [ALC880_W810] = {
e9edcee0 1720 .mixers = { alc880_w810_base_mixer },
b0af0de5
TI
1721 .init_verbs = { alc880_volume_init_verbs, alc880_pin_w810_init_verbs,
1722 alc880_gpio2_init_verbs },
16ded525
TI
1723 .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
1724 .dac_nids = alc880_w810_dac_nids,
1725 .dig_out_nid = ALC880_DIGOUT_NID,
16ded525
TI
1726 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
1727 .channel_mode = alc880_w810_modes,
1728 .input_mux = &alc880_capture_source,
1729 },
1730 [ALC880_Z71V] = {
e9edcee0 1731 .mixers = { alc880_z71v_mixer },
b0af0de5 1732 .init_verbs = { alc880_volume_init_verbs, alc880_pin_z71v_init_verbs },
16ded525
TI
1733 .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
1734 .dac_nids = alc880_z71v_dac_nids,
1735 .dig_out_nid = ALC880_DIGOUT_NID,
1736 .hp_nid = 0x03,
e9edcee0
TI
1737 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
1738 .channel_mode = alc880_2_jack_modes,
16ded525
TI
1739 .input_mux = &alc880_capture_source,
1740 },
1741 [ALC880_F1734] = {
e9edcee0
TI
1742 .mixers = { alc880_f1734_mixer },
1743 .init_verbs = { alc880_volume_init_verbs, alc880_pin_f1734_init_verbs },
1744 .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
1745 .dac_nids = alc880_f1734_dac_nids,
1746 .hp_nid = 0x02,
1747 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
1748 .channel_mode = alc880_2_jack_modes,
16ded525
TI
1749 .input_mux = &alc880_capture_source,
1750 },
1751 [ALC880_ASUS] = {
e9edcee0
TI
1752 .mixers = { alc880_asus_mixer },
1753 .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs,
1754 alc880_gpio1_init_verbs },
1755 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
1756 .dac_nids = alc880_asus_dac_nids,
1757 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
1758 .channel_mode = alc880_asus_modes,
16ded525
TI
1759 .input_mux = &alc880_capture_source,
1760 },
1761 [ALC880_ASUS_DIG] = {
e9edcee0
TI
1762 .mixers = { alc880_asus_mixer },
1763 .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs,
1764 alc880_gpio1_init_verbs },
1765 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
1766 .dac_nids = alc880_asus_dac_nids,
16ded525 1767 .dig_out_nid = ALC880_DIGOUT_NID,
e9edcee0
TI
1768 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
1769 .channel_mode = alc880_asus_modes,
16ded525
TI
1770 .input_mux = &alc880_capture_source,
1771 },
1772 [ALC880_ASUS_W1V] = {
e9edcee0
TI
1773 .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer },
1774 .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs,
1775 alc880_gpio1_init_verbs },
1776 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
1777 .dac_nids = alc880_asus_dac_nids,
16ded525 1778 .dig_out_nid = ALC880_DIGOUT_NID,
e9edcee0
TI
1779 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
1780 .channel_mode = alc880_asus_modes,
16ded525
TI
1781 .input_mux = &alc880_capture_source,
1782 },
1783 [ALC880_UNIWILL_DIG] = {
3c10a9d9 1784 .mixers = { alc880_asus_mixer, alc880_pcbeep_mixer },
e9edcee0
TI
1785 .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs },
1786 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
1787 .dac_nids = alc880_asus_dac_nids,
16ded525 1788 .dig_out_nid = ALC880_DIGOUT_NID,
e9edcee0
TI
1789 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
1790 .channel_mode = alc880_asus_modes,
16ded525
TI
1791 .input_mux = &alc880_capture_source,
1792 },
1793#ifdef CONFIG_SND_DEBUG
1794 [ALC880_TEST] = {
e9edcee0
TI
1795 .mixers = { alc880_test_mixer },
1796 .init_verbs = { alc880_test_init_verbs },
16ded525
TI
1797 .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
1798 .dac_nids = alc880_test_dac_nids,
1799 .dig_out_nid = ALC880_DIGOUT_NID,
16ded525
TI
1800 .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
1801 .channel_mode = alc880_test_modes,
1802 .input_mux = &alc880_test_capture_source,
1803 },
1804#endif
1805};
1806
e9edcee0
TI
1807/*
1808 * Automatic parse of I/O pins from the BIOS configuration
1809 */
1810
1811#define NUM_CONTROL_ALLOC 32
1812#define NUM_VERB_ALLOC 32
1813
1814enum {
1815 ALC_CTL_WIDGET_VOL,
1816 ALC_CTL_WIDGET_MUTE,
1817 ALC_CTL_BIND_MUTE,
1818};
1819static snd_kcontrol_new_t alc880_control_templates[] = {
1820 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
1821 HDA_CODEC_MUTE(NULL, 0, 0, 0),
1822 ALC_BIND_MUTE(NULL, 0, 0, 0),
1823};
1824
1825/* add dynamic controls */
1826static int add_control(struct alc_spec *spec, int type, const char *name, unsigned long val)
1827{
1828 snd_kcontrol_new_t *knew;
1829
1830 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
1831 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
1832
1833 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */
1834 if (! knew)
1835 return -ENOMEM;
1836 if (spec->kctl_alloc) {
1837 memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc);
1838 kfree(spec->kctl_alloc);
1839 }
1840 spec->kctl_alloc = knew;
1841 spec->num_kctl_alloc = num;
1842 }
1843
1844 knew = &spec->kctl_alloc[spec->num_kctl_used];
1845 *knew = alc880_control_templates[type];
543537bd 1846 knew->name = kstrdup(name, GFP_KERNEL);
e9edcee0
TI
1847 if (! knew->name)
1848 return -ENOMEM;
1849 knew->private_value = val;
1850 spec->num_kctl_used++;
1851 return 0;
1852}
1853
1854#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
1855#define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
1856#define alc880_is_multi_pin(nid) ((nid) >= 0x18)
1857#define alc880_multi_pin_idx(nid) ((nid) - 0x18)
1858#define alc880_is_input_pin(nid) ((nid) >= 0x18)
1859#define alc880_input_pin_idx(nid) ((nid) - 0x18)
1860#define alc880_idx_to_dac(nid) ((nid) + 0x02)
1861#define alc880_dac_to_idx(nid) ((nid) - 0x02)
1862#define alc880_idx_to_mixer(nid) ((nid) + 0x0c)
1863#define alc880_idx_to_selector(nid) ((nid) + 0x10)
1864#define ALC880_PIN_CD_NID 0x1c
1865
1866/* fill in the dac_nids table from the parsed pin configuration */
1867static int alc880_auto_fill_dac_nids(struct alc_spec *spec, const struct auto_pin_cfg *cfg)
1868{
1869 hda_nid_t nid;
1870 int assigned[4];
1871 int i, j;
1872
1873 memset(assigned, 0, sizeof(assigned));
b0af0de5 1874 spec->multiout.dac_nids = spec->private_dac_nids;
e9edcee0
TI
1875
1876 /* check the pins hardwired to audio widget */
1877 for (i = 0; i < cfg->line_outs; i++) {
1878 nid = cfg->line_out_pins[i];
1879 if (alc880_is_fixed_pin(nid)) {
1880 int idx = alc880_fixed_pin_idx(nid);
1881 spec->multiout.dac_nids[i] = alc880_dac_to_idx(idx);
1882 assigned[idx] = 1;
1883 }
1884 }
1885 /* left pins can be connect to any audio widget */
1886 for (i = 0; i < cfg->line_outs; i++) {
1887 nid = cfg->line_out_pins[i];
1888 if (alc880_is_fixed_pin(nid))
1889 continue;
1890 /* search for an empty channel */
1891 for (j = 0; j < cfg->line_outs; j++) {
1892 if (! assigned[j]) {
1893 spec->multiout.dac_nids[i] = alc880_idx_to_dac(j);
1894 assigned[j] = 1;
1895 break;
1896 }
1897 }
1898 }
1899 spec->multiout.num_dacs = cfg->line_outs;
1900 return 0;
1901}
1902
1903/* add playback controls from the parsed DAC table */
1904static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg)
1905{
1906 char name[32];
1907 static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" };
1908 hda_nid_t nid;
1909 int i, err;
1910
1911 for (i = 0; i < cfg->line_outs; i++) {
1912 if (! spec->multiout.dac_nids[i])
1913 continue;
1914 nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
1915 if (i == 2) {
1916 /* Center/LFE */
1917 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Center Playback Volume",
1918 HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT))) < 0)
1919 return err;
1920 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "LFE Playback Volume",
1921 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0)
1922 return err;
1923 if ((err = add_control(spec, ALC_CTL_BIND_MUTE, "Center Playback Switch",
1924 HDA_COMPOSE_AMP_VAL(nid, 1, 2, HDA_INPUT))) < 0)
1925 return err;
1926 if ((err = add_control(spec, ALC_CTL_BIND_MUTE, "LFE Playback Switch",
1927 HDA_COMPOSE_AMP_VAL(nid, 2, 2, HDA_INPUT))) < 0)
1928 return err;
1929 } else {
1930 sprintf(name, "%s Playback Volume", chname[i]);
1931 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
1932 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
1933 return err;
1934 sprintf(name, "%s Playback Switch", chname[i]);
1935 if ((err = add_control(spec, ALC_CTL_BIND_MUTE, name,
1936 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT))) < 0)
1937 return err;
1938 }
1939 }
1940
1941 return 0;
1942}
1943
1944/* add playback controls for HP output */
1945static int alc880_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin)
1946{
1947 hda_nid_t nid;
1948 int err;
1949
1950 if (! pin)
1951 return 0;
1952
1953 if (alc880_is_fixed_pin(pin)) {
1954 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
1955 if (! spec->multiout.dac_nids[0]) {
1956 /* use this as the primary output */
1957 spec->multiout.dac_nids[0] = nid;
1958 if (! spec->multiout.num_dacs)
1959 spec->multiout.num_dacs = 1;
1960 } else
1961 /* specify the DAC as the extra HP output */
1962 spec->multiout.hp_nid = nid;
1963 /* control HP volume/switch on the output mixer amp */
1964 nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
1965 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Headphone Playback Volume",
1966 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
1967 return err;
1968 if ((err = add_control(spec, ALC_CTL_BIND_MUTE, "Headphone Playback Switch",
1969 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT))) < 0)
1970 return err;
1971 } else if (alc880_is_multi_pin(pin)) {
1972 /* set manual connection */
1973 if (! spec->multiout.dac_nids[0]) {
1974 /* use this as the primary output */
1975 spec->multiout.dac_nids[0] = alc880_idx_to_dac(alc880_multi_pin_idx(pin));
1976 if (! spec->multiout.num_dacs)
1977 spec->multiout.num_dacs = 1;
1978 }
1979 /* we have only a switch on HP-out PIN */
1980 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Headphone Playback Switch",
1981 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT))) < 0)
1982 return err;
1983 }
1984 return 0;
1985}
1986
1987/* create input playback/capture controls for the given pin */
1988static int new_analog_input(struct alc_spec *spec, hda_nid_t pin, const char *ctlname)
1989{
1990 char name[32];
1991 int err, idx;
1992
1993 sprintf(name, "%s Playback Volume", ctlname);
1994 idx = alc880_input_pin_idx(pin);
1995 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
1996 HDA_COMPOSE_AMP_VAL(0x0b, 3, idx, HDA_INPUT))) < 0)
1997 return err;
1998 sprintf(name, "%s Playback Switch", ctlname);
1999 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
2000 HDA_COMPOSE_AMP_VAL(0x0b, 3, idx, HDA_INPUT))) < 0)
2001 return err;
2002 return 0;
2003}
2004
2005/* create playback/capture controls for input pins */
2006static int alc880_auto_create_analog_input_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg)
2007{
2008 static char *labels[AUTO_PIN_LAST] = {
2009 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux"
2010 };
2011 struct hda_input_mux *imux = &spec->private_imux;
2012 int i, err;
2013
2014 for (i = 0; i < AUTO_PIN_LAST; i++) {
2015 if (alc880_is_input_pin(cfg->input_pins[i])) {
2016 err = new_analog_input(spec, cfg->input_pins[i], labels[i]);
2017 if (err < 0)
2018 return err;
2019 imux->items[imux->num_items].label = labels[i];
2020 imux->items[imux->num_items].index = alc880_input_pin_idx(cfg->input_pins[i]);
2021 imux->num_items++;
2022 }
2023 }
2024 return 0;
2025}
2026
2027static void alc880_auto_set_output_and_unmute(struct hda_codec *codec, hda_nid_t nid, int pin_type,
2028 int dac_idx)
2029{
2030 /* set as output */
2031 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
2032 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
2033 /* need the manual connection? */
2034 if (alc880_is_multi_pin(nid)) {
2035 struct alc_spec *spec = codec->spec;
2036 int idx = alc880_multi_pin_idx(nid);
2037 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
2038 AC_VERB_SET_CONNECT_SEL,
2039 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
2040 }
2041}
2042
2043static void alc880_auto_init_multi_out(struct hda_codec *codec)
2044{
2045 struct alc_spec *spec = codec->spec;
2046 int i;
2047
2048 for (i = 0; i < spec->autocfg.line_outs; i++) {
2049 hda_nid_t nid = spec->autocfg.line_out_pins[i];
2050 alc880_auto_set_output_and_unmute(codec, nid, PIN_OUT, i);
2051 }
2052}
2053
2054static void alc880_auto_init_hp_out(struct hda_codec *codec)
2055{
2056 struct alc_spec *spec = codec->spec;
2057 hda_nid_t pin;
2058
2059 pin = spec->autocfg.hp_pin;
2060 if (pin) /* connect to front */
2061 alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
2062}
2063
2064static void alc880_auto_init_analog_input(struct hda_codec *codec)
2065{
2066 struct alc_spec *spec = codec->spec;
2067 int i;
2068
2069 for (i = 0; i < AUTO_PIN_LAST; i++) {
2070 hda_nid_t nid = spec->autocfg.input_pins[i];
2071 if (alc880_is_input_pin(nid)) {
2072 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
2073 i <= AUTO_PIN_FRONT_MIC ? PIN_VREF80 : PIN_IN);
2074 if (nid != ALC880_PIN_CD_NID)
2075 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
2076 AMP_OUT_MUTE);
2077 }
2078 }
2079}
2080
2081/* parse the BIOS configuration and set up the alc_spec */
2082/* return 1 if successful, 0 if the proper config is not found, or a negative error code */
2083static int alc880_parse_auto_config(struct hda_codec *codec)
2084{
2085 struct alc_spec *spec = codec->spec;
2086 int err;
2087
2088 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg)) < 0)
2089 return err;
2090 if ((err = alc880_auto_fill_dac_nids(spec, &spec->autocfg)) < 0)
2091 return err;
2092 if (! spec->autocfg.line_outs && ! spec->autocfg.hp_pin)
2093 return 0; /* can't find valid BIOS pin config */
2094 if ((err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 ||
2095 (err = alc880_auto_create_hp_ctls(spec, spec->autocfg.hp_pin)) < 0 ||
2096 (err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
2097 return err;
2098
2099 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
2100
2101 if (spec->autocfg.dig_out_pin)
2102 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
2103 if (spec->autocfg.dig_in_pin)
2104 spec->dig_in_nid = ALC880_DIGIN_NID;
2105
2106 if (spec->kctl_alloc)
2107 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2108
2109 spec->init_verbs[spec->num_init_verbs++] = alc880_volume_init_verbs;
2110
2111 spec->input_mux = &spec->private_imux;
2112
2113 return 1;
2114}
2115
2116/* init callback for auto-configuration model -- overriding the default init */
2117static int alc880_auto_init(struct hda_codec *codec)
2118{
2119 alc_init(codec);
2120 alc880_auto_init_multi_out(codec);
2121 alc880_auto_init_hp_out(codec);
2122 alc880_auto_init_analog_input(codec);
2123 return 0;
2124}
2125
2126/*
2127 * OK, here we have finally the patch for ALC880
2128 */
2129
1da177e4
LT
2130static int patch_alc880(struct hda_codec *codec)
2131{
2132 struct alc_spec *spec;
2133 int board_config;
e9edcee0 2134 int i, err;
1da177e4 2135
e560d8d8 2136 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1da177e4
LT
2137 if (spec == NULL)
2138 return -ENOMEM;
2139
41e41f1f 2140 init_MUTEX(&spec->bind_mutex);
1da177e4
LT
2141 codec->spec = spec;
2142
2143 board_config = snd_hda_check_board_config(codec, alc880_cfg_tbl);
16ded525 2144 if (board_config < 0 || board_config >= ALC880_MODEL_LAST) {
e9edcee0
TI
2145 printk(KERN_INFO "hda_codec: Unknown model for ALC880, trying auto-probe from BIOS...\n");
2146 board_config = ALC880_AUTO;
1da177e4 2147 }
1da177e4 2148
e9edcee0
TI
2149 if (board_config == ALC880_AUTO) {
2150 /* automatic parse from the BIOS config */
2151 err = alc880_parse_auto_config(codec);
2152 if (err < 0) {
2153 alc_free(codec);
2154 return err;
2155 } else if (! err) {
2156 printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using 3-stack mode...\n");
2157 board_config = ALC880_3ST;
2158 }
1da177e4
LT
2159 }
2160
e9edcee0
TI
2161 if (board_config != ALC880_AUTO) {
2162 /* set up from the preset table */
2163 const struct alc_config_preset *preset;
2164
2165 preset = &alc880_presets[board_config];
2166
2167 for (i = 0; preset->mixers[i]; i++) {
2168 snd_assert(spec->num_mixers < ARRAY_SIZE(spec->mixers), break);
2169 spec->mixers[spec->num_mixers++] = preset->mixers[i];
2170 }
2171 for (i = 0; preset->init_verbs[i]; i++) {
2172 snd_assert(spec->num_init_verbs < ARRAY_SIZE(spec->init_verbs), break);
2173 spec->init_verbs[spec->num_init_verbs++] = preset->init_verbs[i];
2174 }
2175
2176 spec->channel_mode = preset->channel_mode;
2177 spec->num_channel_mode = preset->num_channel_mode;
2178
2179 spec->multiout.max_channels = spec->channel_mode[0].channels;
2180
2181 spec->multiout.num_dacs = preset->num_dacs;
2182 spec->multiout.dac_nids = preset->dac_nids;
2183 spec->multiout.dig_out_nid = preset->dig_out_nid;
2184 spec->multiout.hp_nid = preset->hp_nid;
2185
2186 spec->input_mux = preset->input_mux;
2187
2188 spec->num_adc_nids = preset->num_adc_nids;
2189 spec->adc_nids = preset->adc_nids;
2190 }
1da177e4
LT
2191
2192 spec->stream_name_analog = "ALC880 Analog";
2193 spec->stream_analog_playback = &alc880_pcm_analog_playback;
2194 spec->stream_analog_capture = &alc880_pcm_analog_capture;
2195
2196 spec->stream_name_digital = "ALC880 Digital";
2197 spec->stream_digital_playback = &alc880_pcm_digital_playback;
2198 spec->stream_digital_capture = &alc880_pcm_digital_capture;
2199
e9edcee0
TI
2200 if (! spec->adc_nids && spec->input_mux) {
2201 /* check whether NID 0x07 is valid */
2202 unsigned int wcap = snd_hda_param_read(codec, alc880_adc_nids[0],
2203 AC_PAR_AUDIO_WIDGET_CAP);
2204 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */
2205 if (wcap != AC_WID_AUD_IN) {
2206 spec->adc_nids = alc880_adc_nids_alt;
2207 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
2208 spec->mixers[spec->num_mixers] = alc880_capture_alt_mixer;
2209 spec->num_mixers++;
2210 } else {
2211 spec->adc_nids = alc880_adc_nids;
2212 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
2213 spec->mixers[spec->num_mixers] = alc880_capture_mixer;
2214 spec->num_mixers++;
2215 }
2216 }
1da177e4
LT
2217
2218 codec->patch_ops = alc_patch_ops;
e9edcee0
TI
2219 if (board_config == ALC880_AUTO)
2220 codec->patch_ops.init = alc880_auto_init;
1da177e4
LT
2221
2222 return 0;
2223}
2224
e9edcee0 2225
1da177e4
LT
2226/*
2227 * ALC260 support
2228 */
2229
e9edcee0
TI
2230static hda_nid_t alc260_dac_nids[1] = {
2231 /* front */
2232 0x02,
2233};
2234
2235static hda_nid_t alc260_adc_nids[1] = {
2236 /* ADC0 */
2237 0x04,
2238};
2239
2240static hda_nid_t alc260_hp_adc_nids[1] = {
2241 /* ADC1 */
2242 0x05,
2243};
2244
2245#define ALC260_DIGOUT_NID 0x03
2246#define ALC260_DIGIN_NID 0x06
2247
2248static struct hda_input_mux alc260_capture_source = {
2249 .num_items = 4,
2250 .items = {
2251 { "Mic", 0x0 },
2252 { "Front Mic", 0x1 },
2253 { "Line", 0x2 },
2254 { "CD", 0x4 },
2255 },
2256};
2257
a9430dd8
JW
2258/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack
2259 * and the internal CD lines.
2260 */
2261static struct hda_input_mux alc260_fujitsu_capture_source = {
2262 .num_items = 2,
2263 .items = {
2264 { "Mic/Line", 0x0 },
2265 { "CD", 0x4 },
2266 },
2267};
2268
1da177e4
LT
2269/*
2270 * This is just place-holder, so there's something for alc_build_pcms to look
2271 * at when it calculates the maximum number of channels. ALC260 has no mixer
2272 * element which allows changing the channel mode, so the verb list is
2273 * never used.
2274 */
2275static struct alc_channel_mode alc260_modes[1] = {
2276 { 2, NULL },
2277};
2278
e9edcee0 2279static snd_kcontrol_new_t alc260_base_mixer[] = {
05acb863
TI
2280 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
2281 ALC_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
1da177e4
LT
2282 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
2283 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
2284 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
2285 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
2286 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
2287 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
2288 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
2289 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
2290 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x07, 0x05, HDA_INPUT),
2291 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x07, 0x05, HDA_INPUT),
05acb863
TI
2292 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
2293 ALC_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
2294 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
a7175aab 2295 ALC_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
1da177e4
LT
2296 HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT),
2297 HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT),
2298 {
2299 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2300 .name = "Capture Source",
2301 .info = alc_mux_enum_info,
2302 .get = alc_mux_enum_get,
2303 .put = alc_mux_enum_put,
2304 },
2305 { } /* end */
2306};
2307
e9edcee0 2308static snd_kcontrol_new_t alc260_hp_mixer[] = {
16ded525
TI
2309 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
2310 ALC_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
2311 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
2312 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
2313 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
2314 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
2315 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
2316 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
2317 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
2318 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
2319 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
2320 ALC_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
2321 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
a7175aab 2322 ALC_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
16ded525
TI
2323 HDA_CODEC_VOLUME("Capture Volume", 0x05, 0x0, HDA_INPUT),
2324 HDA_CODEC_MUTE("Capture Switch", 0x05, 0x0, HDA_INPUT),
2325 {
2326 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2327 .name = "Capture Source",
2328 .info = alc_mux_enum_info,
2329 .get = alc_mux_enum_get,
2330 .put = alc_mux_enum_put,
2331 },
2332 { } /* end */
2333};
2334
a9430dd8
JW
2335static snd_kcontrol_new_t alc260_fujitsu_mixer[] = {
2336 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
2337 ALC_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
2338 ALC_PINCTL_SWITCH("Headphone Amp Switch", 0x14, PIN_HP_AMP),
2339 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
2340 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
2341 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
2342 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
2343 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
2344 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
2345 HDA_CODEC_VOLUME("Internal Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
2346 ALC_BIND_MUTE("Internal Speaker Playback Switch", 0x09, 2, HDA_INPUT),
2347 HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT),
2348 HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT),
2349 {
2350 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2351 .name = "Capture Source",
2352 .info = alc_mux_enum_info,
2353 .get = alc_mux_enum_get,
2354 .put = alc_mux_enum_put,
2355 },
2356 { } /* end */
2357};
2358
1da177e4
LT
2359static struct hda_verb alc260_init_verbs[] = {
2360 /* Line In pin widget for input */
05acb863 2361 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1da177e4 2362 /* CD pin widget for input */
05acb863 2363 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1da177e4 2364 /* Mic1 (rear panel) pin widget for input and vref at 80% */
16ded525 2365 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1da177e4 2366 /* Mic2 (front panel) pin widget for input and vref at 80% */
16ded525 2367 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1da177e4 2368 /* LINE-2 is used for line-out in rear */
05acb863 2369 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1da177e4
LT
2370 /* select line-out */
2371 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
2372 /* LINE-OUT pin */
05acb863 2373 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1da177e4 2374 /* enable HP */
05acb863 2375 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1da177e4 2376 /* enable Mono */
05acb863
TI
2377 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2378 /* mute capture amp left and right */
16ded525 2379 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1da177e4
LT
2380 /* set connection select to line in (default select for this ADC) */
2381 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
16ded525
TI
2382 /* mute capture amp left and right */
2383 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2384 /* set connection select to line in (default select for this ADC) */
2385 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
05acb863
TI
2386 /* set vol=0 Line-Out mixer amp left and right */
2387 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2388 /* unmute pin widget amp left and right (no gain on this amp) */
2389 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2390 /* set vol=0 HP mixer amp left and right */
2391 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2392 /* unmute pin widget amp left and right (no gain on this amp) */
2393 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2394 /* set vol=0 Mono mixer amp left and right */
2395 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2396 /* unmute pin widget amp left and right (no gain on this amp) */
2397 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2398 /* unmute LINE-2 out pin */
2399 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1da177e4 2400 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */
05acb863 2401 /* mute CD */
16ded525 2402 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
05acb863 2403 /* mute Line In */
16ded525 2404 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
05acb863 2405 /* mute Mic */
16ded525 2406 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1da177e4 2407 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
05acb863
TI
2408 /* mute Front out path */
2409 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2410 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2411 /* mute Headphone out path */
2412 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2413 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2414 /* mute Mono out path */
2415 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2416 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1da177e4
LT
2417 { }
2418};
2419
a9430dd8
JW
2420/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
2421 * laptops.
2422 */
2423static struct hda_verb alc260_fujitsu_init_verbs[] = {
2424 /* Disable all GPIOs */
2425 {0x01, AC_VERB_SET_GPIO_MASK, 0},
2426 /* Internal speaker is connected to headphone pin */
2427 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2428 /* Headphone/Line-out jack connects to Line1 pin; make it an output */
2429 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2430 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
2431 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2432 /* Ensure all other unused pins are disabled and muted.
2433 * Note: trying to set widget 0x15 to anything blocks all audio
2434 * output for some reason, so just leave that at the default.
2435 */
2436 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2437 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2438 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2439 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2440 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2441 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2442 /* Disable digital (SPDIF) pins */
2443 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
2444 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
2445
2446 /* Start with mixer outputs muted */
2447 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2448 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2449 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2450
2451 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
2452 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2453 /* Unmute Line1 pin widget amp left and right (no equiv mixer ctrl) */
2454 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2455 /* Unmute pin widget used for Line-in (no equiv mixer ctrl) */
2456 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2457
2458 /* Mute capture amp left and right */
2459 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2460 /* Set ADC connection select to line in (on mic1 pin) */
2461 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
2462
2463 /* Mute all inputs to mixer widget (even unconnected ones) */
2464 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
2465 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
2466 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
2467 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
2468 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
2469 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
2470 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
2471 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
2472};
2473
1da177e4
LT
2474static struct hda_pcm_stream alc260_pcm_analog_playback = {
2475 .substreams = 1,
2476 .channels_min = 2,
2477 .channels_max = 2,
1da177e4
LT
2478};
2479
2480static struct hda_pcm_stream alc260_pcm_analog_capture = {
2481 .substreams = 1,
2482 .channels_min = 2,
2483 .channels_max = 2,
1da177e4
LT
2484};
2485
16ded525
TI
2486static struct hda_board_config alc260_cfg_tbl[] = {
2487 { .modelname = "hp", .config = ALC260_HP },
2488 { .pci_subvendor = 0x103c, .config = ALC260_HP },
a9430dd8
JW
2489 { .modelname = "fujitsu", .config = ALC260_FUJITSU_S702x },
2490 { .pci_subvendor = 0x10cf, .pci_subdevice = 0x1326, .config = ALC260_FUJITSU_S702x },
16ded525
TI
2491 {}
2492};
2493
1da177e4
LT
2494static int patch_alc260(struct hda_codec *codec)
2495{
2496 struct alc_spec *spec;
16ded525 2497 int board_config;
1da177e4 2498
e560d8d8 2499 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1da177e4
LT
2500 if (spec == NULL)
2501 return -ENOMEM;
2502
41e41f1f 2503 init_MUTEX(&spec->bind_mutex);
1da177e4
LT
2504 codec->spec = spec;
2505
16ded525
TI
2506 board_config = snd_hda_check_board_config(codec, alc260_cfg_tbl);
2507 if (board_config < 0 || board_config >= ALC260_MODEL_LAST) {
2508 snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260\n");
2509 board_config = ALC260_BASIC;
2510 }
2511
2512 switch (board_config) {
2513 case ALC260_HP:
e9edcee0 2514 spec->mixers[spec->num_mixers] = alc260_hp_mixer;
16ded525
TI
2515 spec->num_mixers++;
2516 break;
a9430dd8
JW
2517 case ALC260_FUJITSU_S702x:
2518 spec->mixers[spec->num_mixers] = alc260_fujitsu_mixer;
2519 spec->num_mixers++;
2520 break;
16ded525
TI
2521 default:
2522 spec->mixers[spec->num_mixers] = alc260_base_mixer;
2523 spec->num_mixers++;
2524 break;
2525 }
1da177e4 2526
a9430dd8
JW
2527 if (board_config != ALC260_FUJITSU_S702x) {
2528 spec->init_verbs[0] = alc260_init_verbs;
2529 spec->num_init_verbs = 1;
2530 } else {
2531 spec->init_verbs[0] = alc260_fujitsu_init_verbs;
2532 spec->num_init_verbs = 1;
2533 }
e9edcee0 2534
1da177e4
LT
2535 spec->channel_mode = alc260_modes;
2536 spec->num_channel_mode = ARRAY_SIZE(alc260_modes);
2537
2538 spec->stream_name_analog = "ALC260 Analog";
2539 spec->stream_analog_playback = &alc260_pcm_analog_playback;
2540 spec->stream_analog_capture = &alc260_pcm_analog_capture;
2541
2542 spec->multiout.max_channels = spec->channel_mode[0].channels;
2543 spec->multiout.num_dacs = ARRAY_SIZE(alc260_dac_nids);
2544 spec->multiout.dac_nids = alc260_dac_nids;
2545
a9430dd8
JW
2546 if (board_config != ALC260_FUJITSU_S702x) {
2547 spec->input_mux = &alc260_capture_source;
2548 } else {
2549 spec->input_mux = &alc260_fujitsu_capture_source;
2550 }
16ded525
TI
2551 switch (board_config) {
2552 case ALC260_HP:
16ded525
TI
2553 spec->num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids);
2554 spec->adc_nids = alc260_hp_adc_nids;
2555 break;
2556 default:
2557 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
2558 spec->adc_nids = alc260_adc_nids;
2559 break;
2560 }
1da177e4
LT
2561
2562 codec->patch_ops = alc_patch_ops;
2563
2564 return 0;
2565}
2566
e9edcee0 2567
1da177e4
LT
2568/*
2569 * ALC882 support
2570 *
2571 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
2572 * configuration. Each pin widget can choose any input DACs and a mixer.
2573 * Each ADC is connected from a mixer of all inputs. This makes possible
2574 * 6-channel independent captures.
2575 *
2576 * In addition, an independent DAC for the multi-playback (not used in this
2577 * driver yet).
2578 */
2579
2580static struct alc_channel_mode alc882_ch_modes[1] = {
2581 { 8, NULL }
2582};
2583
2584static hda_nid_t alc882_dac_nids[4] = {
2585 /* front, rear, clfe, rear_surr */
2586 0x02, 0x03, 0x04, 0x05
2587};
2588
2589static hda_nid_t alc882_adc_nids[3] = {
2590 /* ADC0-2 */
2591 0x07, 0x08, 0x09,
2592};
2593
2594/* input MUX */
2595/* FIXME: should be a matrix-type input source selection */
2596
2597static struct hda_input_mux alc882_capture_source = {
2598 .num_items = 4,
2599 .items = {
2600 { "Mic", 0x0 },
2601 { "Front Mic", 0x1 },
2602 { "Line", 0x2 },
2603 { "CD", 0x4 },
2604 },
2605};
2606
2607#define alc882_mux_enum_info alc_mux_enum_info
2608#define alc882_mux_enum_get alc_mux_enum_get
2609
2610static int alc882_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
2611{
2612 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2613 struct alc_spec *spec = codec->spec;
2614 const struct hda_input_mux *imux = spec->input_mux;
2615 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
2616 static hda_nid_t capture_mixers[3] = { 0x24, 0x23, 0x22 };
2617 hda_nid_t nid = capture_mixers[adc_idx];
2618 unsigned int *cur_val = &spec->cur_mux[adc_idx];
2619 unsigned int i, idx;
2620
2621 idx = ucontrol->value.enumerated.item[0];
2622 if (idx >= imux->num_items)
2623 idx = imux->num_items - 1;
2624 if (*cur_val == idx && ! codec->in_resume)
2625 return 0;
2626 for (i = 0; i < imux->num_items; i++) {
2627 unsigned int v = (i == idx) ? 0x7000 : 0x7080;
2628 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
2629 v | (imux->items[i].index << 8));
2630 }
2631 *cur_val = idx;
2632 return 1;
2633}
2634
2635/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
2636 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
2637 */
2638static snd_kcontrol_new_t alc882_base_mixer[] = {
05acb863
TI
2639 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2640 ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2641 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2642 ALC_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
2643 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2644 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2645 ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
92447f3f 2646 ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
05acb863
TI
2647 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2648 ALC_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
1da177e4
LT
2649 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
2650 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2651 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2652 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2653 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2654 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2655 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2656 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2657 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
2658 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
2659 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
2660 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
2661 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
2662 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
2663 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
2664 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
2665 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
2666 {
2667 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2668 /* .name = "Capture Source", */
2669 .name = "Input Source",
2670 .count = 3,
2671 .info = alc882_mux_enum_info,
2672 .get = alc882_mux_enum_get,
2673 .put = alc882_mux_enum_put,
2674 },
2675 { } /* end */
2676};
2677
2678static struct hda_verb alc882_init_verbs[] = {
2679 /* Front mixer: unmute input/output amp left and right (volume = 0) */
05acb863
TI
2680 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2681 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2682 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1da177e4 2683 /* Rear mixer */
05acb863
TI
2684 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2685 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2686 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1da177e4 2687 /* CLFE mixer */
05acb863
TI
2688 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2689 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2690 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1da177e4 2691 /* Side mixer */
05acb863
TI
2692 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2693 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2694 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1da177e4 2695
e9edcee0 2696 /* Front Pin: output 0 (0x0c) */
05acb863 2697 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
05acb863 2698 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1da177e4 2699 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
e9edcee0 2700 /* Rear Pin: output 1 (0x0d) */
05acb863 2701 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
05acb863 2702 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1da177e4 2703 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
e9edcee0 2704 /* CLFE Pin: output 2 (0x0e) */
05acb863 2705 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
05acb863 2706 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1da177e4 2707 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
e9edcee0 2708 /* Side Pin: output 3 (0x0f) */
05acb863 2709 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
05acb863 2710 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1da177e4 2711 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
e9edcee0 2712 /* Mic (rear) pin: input vref at 80% */
16ded525 2713 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
e9edcee0
TI
2714 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2715 /* Front Mic pin: input vref at 80% */
16ded525 2716 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
e9edcee0
TI
2717 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2718 /* Line In pin: input */
05acb863 2719 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
e9edcee0
TI
2720 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2721 /* Line-2 In: Headphone output (output 0 - 0x0c) */
2722 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2723 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2724 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
1da177e4 2725 /* CD pin widget for input */
05acb863 2726 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1da177e4
LT
2727
2728 /* FIXME: use matrix-type input source selection */
2729 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
2730 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
05acb863
TI
2731 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2732 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2733 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2734 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
1da177e4 2735 /* Input mixer2 */
05acb863
TI
2736 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2737 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2738 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2739 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
1da177e4 2740 /* Input mixer3 */
05acb863
TI
2741 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2742 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2743 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2744 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2745 /* ADC1: mute amp left and right */
2746 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
71fe7b82 2747 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
05acb863
TI
2748 /* ADC2: mute amp left and right */
2749 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
71fe7b82 2750 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
05acb863
TI
2751 /* ADC3: mute amp left and right */
2752 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
71fe7b82 2753 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
1da177e4
LT
2754
2755 { }
2756};
2757
2758static int patch_alc882(struct hda_codec *codec)
2759{
2760 struct alc_spec *spec;
2761
e560d8d8 2762 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1da177e4
LT
2763 if (spec == NULL)
2764 return -ENOMEM;
2765
41e41f1f 2766 init_MUTEX(&spec->bind_mutex);
1da177e4
LT
2767 codec->spec = spec;
2768
2769 spec->mixers[spec->num_mixers] = alc882_base_mixer;
2770 spec->num_mixers++;
2771
2772 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
2773 spec->dig_in_nid = ALC880_DIGIN_NID;
e9edcee0
TI
2774 spec->init_verbs[0] = alc882_init_verbs;
2775 spec->num_init_verbs = 1;
2776
1da177e4
LT
2777 spec->channel_mode = alc882_ch_modes;
2778 spec->num_channel_mode = ARRAY_SIZE(alc882_ch_modes);
2779
2780 spec->stream_name_analog = "ALC882 Analog";
2781 spec->stream_analog_playback = &alc880_pcm_analog_playback;
2782 spec->stream_analog_capture = &alc880_pcm_analog_capture;
2783
2784 spec->stream_name_digital = "ALC882 Digital";
2785 spec->stream_digital_playback = &alc880_pcm_digital_playback;
2786 spec->stream_digital_capture = &alc880_pcm_digital_capture;
2787
2788 spec->multiout.max_channels = spec->channel_mode[0].channels;
2789 spec->multiout.num_dacs = ARRAY_SIZE(alc882_dac_nids);
2790 spec->multiout.dac_nids = alc882_dac_nids;
2791
2792 spec->input_mux = &alc882_capture_source;
2793 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids);
2794 spec->adc_nids = alc882_adc_nids;
2795
2796 codec->patch_ops = alc_patch_ops;
2797
2798 return 0;
2799}
2800
2801/*
2802 * patch entries
2803 */
2804struct hda_codec_preset snd_hda_preset_realtek[] = {
2805 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
2806 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
2807 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
2808 {} /* terminator */
2809};