blob: 5de754a51fc71eb04a031b8f671427ccdf5eb36b [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Universal Interface for Intel High Definition Audio Codec
3 *
4 * HD audio interface patch for ALC 260/880/882 codecs
5 *
Kailang Yangdf694da2005-12-05 19:42:22 +01006 * Copyright (c) 2004 Kailang Yang <kailang@realtek.com.tw>
7 * PeiSen Hou <pshou@realtek.com.tw>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * Takashi Iwai <tiwai@suse.de>
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01009 * Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
11 * This driver is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This driver is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
26#include <sound/driver.h>
27#include <linux/init.h>
28#include <linux/delay.h>
29#include <linux/slab.h>
30#include <linux/pci.h>
31#include <sound/core.h>
32#include "hda_codec.h"
33#include "hda_local.h"
34
35
36/* ALC880 board config type */
37enum {
Linus Torvalds1da177e2005-04-16 15:20:36 -070038 ALC880_3ST,
39 ALC880_3ST_DIG,
40 ALC880_5ST,
41 ALC880_5ST_DIG,
42 ALC880_W810,
Takashi Iwaidfc0ff62005-05-12 14:31:49 +020043 ALC880_Z71V,
Takashi Iwaib6482d42005-06-27 15:32:43 +020044 ALC880_6ST,
Takashi Iwai16ded522005-06-10 19:58:24 +020045 ALC880_6ST_DIG,
46 ALC880_F1734,
47 ALC880_ASUS,
48 ALC880_ASUS_DIG,
49 ALC880_ASUS_W1V,
Kailang Yangdf694da2005-12-05 19:42:22 +010050 ALC880_ASUS_DIG2,
Takashi Iwai16ded522005-06-10 19:58:24 +020051 ALC880_UNIWILL_DIG,
Kailang Yangdf694da2005-12-05 19:42:22 +010052 ALC880_CLEVO,
53 ALC880_TCL_S700,
Takashi Iwaie9edcee2005-06-13 14:16:38 +020054#ifdef CONFIG_SND_DEBUG
55 ALC880_TEST,
56#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010057 ALC880_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020058 ALC880_MODEL_LAST /* last tag */
59};
60
61/* ALC260 models */
62enum {
63 ALC260_BASIC,
64 ALC260_HP,
Kailang Yangdf694da2005-12-05 19:42:22 +010065 ALC260_HP_3013,
66 ALC260_FUJITSU_S702X,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +010067 ALC260_ACER,
Jonathan Woithe7cf51e42006-02-09 12:01:26 +010068#ifdef CONFIG_SND_DEBUG
69 ALC260_TEST,
70#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010071 ALC260_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020072 ALC260_MODEL_LAST /* last tag */
Linus Torvalds1da177e2005-04-16 15:20:36 -070073};
74
Kailang Yangdf694da2005-12-05 19:42:22 +010075/* ALC262 models */
76enum {
77 ALC262_BASIC,
Takashi Iwai834be882006-03-01 14:16:17 +010078 ALC262_FUJITSU,
Kailang Yangdf694da2005-12-05 19:42:22 +010079 ALC262_AUTO,
80 ALC262_MODEL_LAST /* last tag */
81};
82
83/* ALC861 models */
84enum {
85 ALC861_3ST,
86 ALC861_3ST_DIG,
87 ALC861_6ST_DIG,
88 ALC861_AUTO,
89 ALC861_MODEL_LAST,
90};
91
92/* ALC882 models */
93enum {
94 ALC882_3ST_DIG,
95 ALC882_6ST_DIG,
96 ALC882_AUTO,
97 ALC882_MODEL_LAST,
98};
99
100/* for GPIO Poll */
101#define GPIO_MASK 0x03
102
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103struct alc_spec {
104 /* codec parameterization */
Kailang Yangdf694da2005-12-05 19:42:22 +0100105 struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 unsigned int num_mixers;
107
Kailang Yangdf694da2005-12-05 19:42:22 +0100108 const struct hda_verb *init_verbs[5]; /* initialization verbs
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200109 * don't forget NULL termination!
110 */
111 unsigned int num_init_verbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112
Takashi Iwai16ded522005-06-10 19:58:24 +0200113 char *stream_name_analog; /* analog PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 struct hda_pcm_stream *stream_analog_playback;
115 struct hda_pcm_stream *stream_analog_capture;
116
Takashi Iwai16ded522005-06-10 19:58:24 +0200117 char *stream_name_digital; /* digital PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 struct hda_pcm_stream *stream_digital_playback;
119 struct hda_pcm_stream *stream_digital_capture;
120
121 /* playback */
Takashi Iwai16ded522005-06-10 19:58:24 +0200122 struct hda_multi_out multiout; /* playback set-up
123 * max_channels, dacs must be set
124 * dig_out_nid and hp_nid are optional
125 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126
127 /* capture */
128 unsigned int num_adc_nids;
129 hda_nid_t *adc_nids;
Takashi Iwai16ded522005-06-10 19:58:24 +0200130 hda_nid_t dig_in_nid; /* digital-in NID; optional */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131
132 /* capture source */
133 const struct hda_input_mux *input_mux;
134 unsigned int cur_mux[3];
135
136 /* channel model */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100137 const struct hda_channel_mode *channel_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 int num_channel_mode;
139
140 /* PCM information */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100141 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
Takashi Iwai41e41f12005-06-08 14:48:49 +0200142
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200143 /* dynamic controls, init_verbs and input_mux */
144 struct auto_pin_cfg autocfg;
145 unsigned int num_kctl_alloc, num_kctl_used;
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +0100146 struct snd_kcontrol_new *kctl_alloc;
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200147 struct hda_input_mux private_imux;
Kailang Yangdf694da2005-12-05 19:42:22 +0100148 hda_nid_t private_dac_nids[5];
Takashi Iwai834be882006-03-01 14:16:17 +0100149
150 /* for pin sensing */
151 unsigned int sense_updated: 1;
152 unsigned int jack_present: 1;
Kailang Yangdf694da2005-12-05 19:42:22 +0100153};
154
155/*
156 * configuration template - to be copied to the spec instance
157 */
158struct alc_config_preset {
159 struct snd_kcontrol_new *mixers[5]; /* should be identical size with spec */
160 const struct hda_verb *init_verbs[5];
161 unsigned int num_dacs;
162 hda_nid_t *dac_nids;
163 hda_nid_t dig_out_nid; /* optional */
164 hda_nid_t hp_nid; /* optional */
165 unsigned int num_adc_nids;
166 hda_nid_t *adc_nids;
167 hda_nid_t dig_in_nid;
168 unsigned int num_channel_mode;
169 const struct hda_channel_mode *channel_mode;
170 const struct hda_input_mux *input_mux;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171};
172
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173
174/*
175 * input MUX handling
176 */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +0100177static int alc_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178{
179 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
180 struct alc_spec *spec = codec->spec;
181 return snd_hda_input_mux_info(spec->input_mux, uinfo);
182}
183
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +0100184static int alc_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185{
186 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
187 struct alc_spec *spec = codec->spec;
188 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
189
190 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
191 return 0;
192}
193
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +0100194static int alc_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195{
196 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
197 struct alc_spec *spec = codec->spec;
198 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
199 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
200 spec->adc_nids[adc_idx], &spec->cur_mux[adc_idx]);
201}
202
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200203
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204/*
205 * channel mode setting
206 */
Kailang Yangdf694da2005-12-05 19:42:22 +0100207static int alc_ch_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208{
209 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
210 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100211 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
212 spec->num_channel_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213}
214
Kailang Yangdf694da2005-12-05 19:42:22 +0100215static int alc_ch_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216{
217 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
218 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100219 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
220 spec->num_channel_mode, spec->multiout.max_channels);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221}
222
Kailang Yangdf694da2005-12-05 19:42:22 +0100223static int alc_ch_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224{
225 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
226 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100227 return snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
228 spec->num_channel_mode, &spec->multiout.max_channels);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229}
230
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231/*
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100232 * Control the mode of pin widget settings via the mixer. "pc" is used
233 * instead of "%" to avoid consequences of accidently treating the % as
234 * being part of a format specifier. Maximum allowed length of a value is
235 * 63 characters plus NULL terminator.
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100236 *
237 * Note: some retasking pin complexes seem to ignore requests for input
238 * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these
239 * are requested. Therefore order this list so that this behaviour will not
240 * cause problems when mixer clients move through the enum sequentially.
241 * NIDs 0x0f and 0x10 have been observed to have this behaviour.
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200242 */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100243static char *alc_pin_mode_names[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100244 "Mic 50pc bias", "Mic 80pc bias",
245 "Line in", "Line out", "Headphone out",
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100246};
247static unsigned char alc_pin_mode_values[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100248 PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100249};
250/* The control can present all 5 options, or it can limit the options based
251 * in the pin being assumed to be exclusively an input or an output pin.
252 */
253#define ALC_PIN_DIR_IN 0x00
254#define ALC_PIN_DIR_OUT 0x01
255#define ALC_PIN_DIR_INOUT 0x02
256
257/* Info about the pin modes supported by the three different pin directions.
258 * For each direction the minimum and maximum values are given.
259 */
260static signed char alc_pin_mode_dir_info[3][2] = {
261 { 0, 2 }, /* ALC_PIN_DIR_IN */
262 { 3, 4 }, /* ALC_PIN_DIR_OUT */
263 { 0, 4 }, /* ALC_PIN_DIR_INOUT */
264};
265#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0])
266#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1])
267#define alc_pin_mode_n_items(_dir) \
268 (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1)
269
270static int alc_pin_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200271{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100272 unsigned int item_num = uinfo->value.enumerated.item;
273 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
274
275 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200276 uinfo->count = 1;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100277 uinfo->value.enumerated.items = alc_pin_mode_n_items(dir);
278
279 if (item_num<alc_pin_mode_min(dir) || item_num>alc_pin_mode_max(dir))
280 item_num = alc_pin_mode_min(dir);
281 strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200282 return 0;
283}
284
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100285static int alc_pin_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200286{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100287 unsigned int i;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200288 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
289 hda_nid_t nid = kcontrol->private_value & 0xffff;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100290 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200291 long *valp = ucontrol->value.integer.value;
292 unsigned int pinctl = snd_hda_codec_read(codec,nid,0,AC_VERB_GET_PIN_WIDGET_CONTROL,0x00);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200293
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100294 /* Find enumerated value for current pinctl setting */
295 i = alc_pin_mode_min(dir);
296 while (alc_pin_mode_values[i]!=pinctl && i<=alc_pin_mode_max(dir))
297 i++;
298 *valp = i<=alc_pin_mode_max(dir)?i:alc_pin_mode_min(dir);
299 return 0;
300}
301
302static int alc_pin_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
303{
304 signed int change;
305 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
306 hda_nid_t nid = kcontrol->private_value & 0xffff;
307 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
308 long val = *ucontrol->value.integer.value;
309 unsigned int pinctl = snd_hda_codec_read(codec,nid,0,AC_VERB_GET_PIN_WIDGET_CONTROL,0x00);
310
311 if (val<alc_pin_mode_min(dir) || val>alc_pin_mode_max(dir))
312 val = alc_pin_mode_min(dir);
313
314 change = pinctl != alc_pin_mode_values[val];
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100315 if (change) {
316 /* Set pin mode to that requested */
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200317 snd_hda_codec_write(codec,nid,0,AC_VERB_SET_PIN_WIDGET_CONTROL,
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100318 alc_pin_mode_values[val]);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100319
320 /* Also enable the retasking pin's input/output as required
321 * for the requested pin mode. Enum values of 2 or less are
322 * input modes.
323 *
324 * Dynamically switching the input/output buffers probably
325 * reduces noise slightly, particularly on input. However,
326 * havingboth input and output buffers enabled
327 * simultaneously doesn't seem to be problematic.
328 */
329 if (val <= 2) {
330 snd_hda_codec_write(codec,nid,0,AC_VERB_SET_AMP_GAIN_MUTE,
331 AMP_OUT_MUTE);
332 snd_hda_codec_write(codec,nid,0,AC_VERB_SET_AMP_GAIN_MUTE,
333 AMP_IN_UNMUTE(0));
334 } else {
335 snd_hda_codec_write(codec,nid,0,AC_VERB_SET_AMP_GAIN_MUTE,
336 AMP_IN_MUTE(0));
337 snd_hda_codec_write(codec,nid,0,AC_VERB_SET_AMP_GAIN_MUTE,
338 AMP_OUT_UNMUTE);
339 }
340 }
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200341 return change;
342}
343
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100344#define ALC_PIN_MODE(xname, nid, dir) \
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200345 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100346 .info = alc_pin_mode_info, \
347 .get = alc_pin_mode_get, \
348 .put = alc_pin_mode_put, \
349 .private_value = nid | (dir<<16) }
Kailang Yangdf694da2005-12-05 19:42:22 +0100350
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100351/* A switch control for ALC260 GPIO pins. Multiple GPIOs can be ganged
352 * together using a mask with more than one bit set. This control is
353 * currently used only by the ALC260 test model. At this stage they are not
354 * needed for any "production" models.
355 */
356#ifdef CONFIG_SND_DEBUG
357static int alc_gpio_data_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
358{
359 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
360 uinfo->count = 1;
361 uinfo->value.integer.min = 0;
362 uinfo->value.integer.max = 1;
363 return 0;
364}
365static int alc_gpio_data_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
366{
367 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
368 hda_nid_t nid = kcontrol->private_value & 0xffff;
369 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
370 long *valp = ucontrol->value.integer.value;
371 unsigned int val = snd_hda_codec_read(codec,nid,0,AC_VERB_GET_GPIO_DATA,0x00);
372
373 *valp = (val & mask) != 0;
374 return 0;
375}
376static int alc_gpio_data_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
377{
378 signed int change;
379 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
380 hda_nid_t nid = kcontrol->private_value & 0xffff;
381 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
382 long val = *ucontrol->value.integer.value;
383 unsigned int gpio_data = snd_hda_codec_read(codec,nid,0,AC_VERB_GET_GPIO_DATA,0x00);
384
385 /* Set/unset the masked GPIO bit(s) as needed */
386 change = (val==0?0:mask) != (gpio_data & mask);
387 if (val==0)
388 gpio_data &= ~mask;
389 else
390 gpio_data |= mask;
391 snd_hda_codec_write(codec,nid,0,AC_VERB_SET_GPIO_DATA,gpio_data);
392
393 return change;
394}
395#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
396 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
397 .info = alc_gpio_data_info, \
398 .get = alc_gpio_data_get, \
399 .put = alc_gpio_data_put, \
400 .private_value = nid | (mask<<16) }
401#endif /* CONFIG_SND_DEBUG */
402
Jonathan Woithe92621f12006-02-28 11:47:47 +0100403/* A switch control to allow the enabling of the digital IO pins on the
404 * ALC260. This is incredibly simplistic; the intention of this control is
405 * to provide something in the test model allowing digital outputs to be
406 * identified if present. If models are found which can utilise these
407 * outputs a more complete mixer control can be devised for those models if
408 * necessary.
409 */
410#ifdef CONFIG_SND_DEBUG
411static int alc_spdif_ctrl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
412{
413 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
414 uinfo->count = 1;
415 uinfo->value.integer.min = 0;
416 uinfo->value.integer.max = 1;
417 return 0;
418}
419static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
420{
421 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
422 hda_nid_t nid = kcontrol->private_value & 0xffff;
423 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
424 long *valp = ucontrol->value.integer.value;
425 unsigned int val = snd_hda_codec_read(codec,nid,0,AC_VERB_GET_DIGI_CONVERT,0x00);
426
427 *valp = (val & mask) != 0;
428 return 0;
429}
430static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
431{
432 signed int change;
433 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
434 hda_nid_t nid = kcontrol->private_value & 0xffff;
435 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
436 long val = *ucontrol->value.integer.value;
437 unsigned int ctrl_data = snd_hda_codec_read(codec,nid,0,AC_VERB_GET_DIGI_CONVERT,0x00);
438
439 /* Set/unset the masked control bit(s) as needed */
440 change = (val==0?0:mask) != (ctrl_data & mask);
441 if (val==0)
442 ctrl_data &= ~mask;
443 else
444 ctrl_data |= mask;
445 snd_hda_codec_write(codec,nid,0,AC_VERB_SET_DIGI_CONVERT_1,ctrl_data);
446
447 return change;
448}
449#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \
450 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
451 .info = alc_spdif_ctrl_info, \
452 .get = alc_spdif_ctrl_get, \
453 .put = alc_spdif_ctrl_put, \
454 .private_value = nid | (mask<<16) }
455#endif /* CONFIG_SND_DEBUG */
456
Kailang Yangdf694da2005-12-05 19:42:22 +0100457/*
458 * set up from the preset table
459 */
460static void setup_preset(struct alc_spec *spec, const struct alc_config_preset *preset)
461{
462 int i;
463
464 for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
465 spec->mixers[spec->num_mixers++] = preset->mixers[i];
466 for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i]; i++)
467 spec->init_verbs[spec->num_init_verbs++] = preset->init_verbs[i];
468
469 spec->channel_mode = preset->channel_mode;
470 spec->num_channel_mode = preset->num_channel_mode;
471
472 spec->multiout.max_channels = spec->channel_mode[0].channels;
473
474 spec->multiout.num_dacs = preset->num_dacs;
475 spec->multiout.dac_nids = preset->dac_nids;
476 spec->multiout.dig_out_nid = preset->dig_out_nid;
477 spec->multiout.hp_nid = preset->hp_nid;
478
479 spec->input_mux = preset->input_mux;
480
481 spec->num_adc_nids = preset->num_adc_nids;
482 spec->adc_nids = preset->adc_nids;
483 spec->dig_in_nid = preset->dig_in_nid;
484}
485
Takashi Iwai41e41f12005-06-08 14:48:49 +0200486/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200487 * ALC880 3-stack model
488 *
489 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
490 * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18, F-Mic = 0x1b
491 * HP = 0x19
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 */
493
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200494static hda_nid_t alc880_dac_nids[4] = {
495 /* front, rear, clfe, rear_surr */
496 0x02, 0x05, 0x04, 0x03
497};
498
499static hda_nid_t alc880_adc_nids[3] = {
500 /* ADC0-2 */
501 0x07, 0x08, 0x09,
502};
503
504/* The datasheet says the node 0x07 is connected from inputs,
505 * but it shows zero connection in the real implementation on some devices.
Kailang Yangdf694da2005-12-05 19:42:22 +0100506 * Note: this is a 915GAV bug, fixed on 915GLV
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200508static hda_nid_t alc880_adc_nids_alt[2] = {
509 /* ADC1-2 */
510 0x08, 0x09,
511};
512
513#define ALC880_DIGOUT_NID 0x06
514#define ALC880_DIGIN_NID 0x0a
515
516static struct hda_input_mux alc880_capture_source = {
517 .num_items = 4,
518 .items = {
519 { "Mic", 0x0 },
520 { "Front Mic", 0x3 },
521 { "Line", 0x2 },
522 { "CD", 0x4 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 },
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200524};
525
526/* channel source setting (2/6 channel selection for 3-stack) */
527/* 2ch mode */
528static struct hda_verb alc880_threestack_ch2_init[] = {
529 /* set line-in to input, mute it */
530 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
531 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
532 /* set mic-in to input vref 80%, mute it */
533 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
534 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 { } /* end */
536};
537
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200538/* 6ch mode */
539static struct hda_verb alc880_threestack_ch6_init[] = {
540 /* set line-in to output, unmute it */
541 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
542 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
543 /* set mic-in to output, unmute it */
544 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
545 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
546 { } /* end */
547};
548
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100549static struct hda_channel_mode alc880_threestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200550 { 2, alc880_threestack_ch2_init },
551 { 6, alc880_threestack_ch6_init },
552};
553
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +0100554static struct snd_kcontrol_new alc880_three_stack_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +0200555 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +0100556 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +0200557 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +0100558 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +0200559 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
560 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +0100561 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
562 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
564 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
565 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
566 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
567 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
568 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
569 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
570 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
571 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
572 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200574 {
575 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
576 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +0100577 .info = alc_ch_mode_info,
578 .get = alc_ch_mode_get,
579 .put = alc_ch_mode_put,
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200580 },
581 { } /* end */
582};
583
584/* capture mixer elements */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +0100585static struct snd_kcontrol_new alc880_capture_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200586 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
587 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
588 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
589 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
590 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
591 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
592 {
593 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
594 /* The multiple "Capture Source" controls confuse alsamixer
595 * So call somewhat different..
596 * FIXME: the controls appear in the "playback" view!
597 */
598 /* .name = "Capture Source", */
599 .name = "Input Source",
600 .count = 3,
601 .info = alc_mux_enum_info,
602 .get = alc_mux_enum_get,
603 .put = alc_mux_enum_put,
604 },
605 { } /* end */
606};
607
608/* capture mixer elements (in case NID 0x07 not available) */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +0100609static struct snd_kcontrol_new alc880_capture_alt_mixer[] = {
Takashi Iwai71fe7b82005-05-25 18:11:40 +0200610 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
611 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
612 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
613 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 {
615 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
616 /* The multiple "Capture Source" controls confuse alsamixer
617 * So call somewhat different..
618 * FIXME: the controls appear in the "playback" view!
619 */
620 /* .name = "Capture Source", */
621 .name = "Input Source",
622 .count = 2,
623 .info = alc_mux_enum_info,
624 .get = alc_mux_enum_get,
625 .put = alc_mux_enum_put,
626 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 { } /* end */
628};
629
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200630
631
632/*
633 * ALC880 5-stack model
634 *
635 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d), Side = 0x02 (0xd)
636 * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
637 * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
638 */
639
640/* additional mixers to alc880_three_stack_mixer */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +0100641static struct snd_kcontrol_new alc880_five_stack_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200642 HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +0100643 HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 { } /* end */
645};
646
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200647/* channel source setting (6/8 channel selection for 5-stack) */
648/* 6ch mode */
649static struct hda_verb alc880_fivestack_ch6_init[] = {
650 /* set line-in to input, mute it */
651 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
652 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Takashi Iwaidfc0ff62005-05-12 14:31:49 +0200653 { } /* end */
654};
655
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200656/* 8ch mode */
657static struct hda_verb alc880_fivestack_ch8_init[] = {
658 /* set line-in to output, unmute it */
659 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
660 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
661 { } /* end */
662};
663
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100664static struct hda_channel_mode alc880_fivestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200665 { 6, alc880_fivestack_ch6_init },
666 { 8, alc880_fivestack_ch8_init },
667};
668
669
670/*
671 * ALC880 6-stack model
672 *
673 * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e), Side = 0x05 (0x0f)
674 * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
675 * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
676 */
677
678static hda_nid_t alc880_6st_dac_nids[4] = {
679 /* front, rear, clfe, rear_surr */
680 0x02, 0x03, 0x04, 0x05
681};
682
683static struct hda_input_mux alc880_6stack_capture_source = {
684 .num_items = 4,
685 .items = {
686 { "Mic", 0x0 },
687 { "Front Mic", 0x1 },
688 { "Line", 0x2 },
689 { "CD", 0x4 },
690 },
691};
692
693/* fixed 8-channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100694static struct hda_channel_mode alc880_sixstack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200695 { 8, NULL },
696};
697
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +0100698static struct snd_kcontrol_new alc880_six_stack_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +0200699 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +0100700 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +0200701 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +0100702 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +0200703 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
704 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +0100705 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
706 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +0200707 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +0100708 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +0200709 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
710 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
711 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
712 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
713 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
714 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
715 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
716 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
717 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
718 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +0200719 {
720 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
721 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +0100722 .info = alc_ch_mode_info,
723 .get = alc_ch_mode_get,
724 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +0200725 },
726 { } /* end */
727};
728
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200729
730/*
731 * ALC880 W810 model
732 *
733 * W810 has rear IO for:
734 * Front (DAC 02)
735 * Surround (DAC 03)
736 * Center/LFE (DAC 04)
737 * Digital out (06)
738 *
739 * The system also has a pair of internal speakers, and a headphone jack.
740 * These are both connected to Line2 on the codec, hence to DAC 02.
741 *
742 * There is a variable resistor to control the speaker or headphone
743 * volume. This is a hardware-only device without a software API.
744 *
745 * Plugging headphones in will disable the internal speakers. This is
746 * implemented in hardware, not via the driver using jack sense. In
747 * a similar fashion, plugging into the rear socket marked "front" will
748 * disable both the speakers and headphones.
749 *
750 * For input, there's a microphone jack, and an "audio in" jack.
751 * These may not do anything useful with this driver yet, because I
752 * haven't setup any initialization verbs for these yet...
753 */
754
755static hda_nid_t alc880_w810_dac_nids[3] = {
756 /* front, rear/surround, clfe */
757 0x02, 0x03, 0x04
758};
759
760/* fixed 6 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100761static struct hda_channel_mode alc880_w810_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200762 { 6, NULL }
763};
764
765/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +0100766static struct snd_kcontrol_new alc880_w810_base_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200767 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +0100768 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200769 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +0100770 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200771 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
772 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +0100773 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
774 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200775 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
776 { } /* end */
777};
778
779
780/*
781 * Z710V model
782 *
783 * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
784 * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?), Line = 0x1a
785 */
786
787static hda_nid_t alc880_z71v_dac_nids[1] = {
788 0x02
789};
790#define ALC880_Z71V_HP_DAC 0x03
791
792/* fixed 2 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100793static struct hda_channel_mode alc880_2_jack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200794 { 2, NULL }
795};
796
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +0100797static struct snd_kcontrol_new alc880_z71v_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200798 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +0100799 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200800 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +0100801 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200802 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
803 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
804 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
805 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
806 { } /* end */
807};
808
809
810/* FIXME! */
811/*
812 * ALC880 F1734 model
813 *
814 * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
815 * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
816 */
817
818static hda_nid_t alc880_f1734_dac_nids[1] = {
819 0x03
820};
821#define ALC880_F1734_HP_DAC 0x02
822
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +0100823static struct snd_kcontrol_new alc880_f1734_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +0200824 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +0100825 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +0200826 HDA_CODEC_VOLUME("Internal Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +0100827 HDA_BIND_MUTE("Internal Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +0200828 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
829 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
830 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
831 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +0200832 { } /* end */
833};
834
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200835
836/* FIXME! */
837/*
838 * ALC880 ASUS model
839 *
840 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
841 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
842 * Mic = 0x18, Line = 0x1a
843 */
844
845#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */
846#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */
847
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +0100848static struct snd_kcontrol_new alc880_asus_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +0200849 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +0100850 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +0200851 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +0100852 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +0200853 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
854 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +0100855 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
856 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +0200857 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
858 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
859 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
860 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
861 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
862 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +0200863 {
864 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
865 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +0100866 .info = alc_ch_mode_info,
867 .get = alc_ch_mode_get,
868 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +0200869 },
870 { } /* end */
871};
872
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200873/* FIXME! */
874/*
875 * ALC880 ASUS W1V model
876 *
877 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
878 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
879 * Mic = 0x18, Line = 0x1a, Line2 = 0x1b
880 */
881
882/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +0100883static struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +0200884 HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
885 HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +0200886 { } /* end */
887};
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200888
Takashi Iwai3c10a9d2005-08-23 20:02:27 +0200889/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +0100890static struct snd_kcontrol_new alc880_pcbeep_mixer[] = {
Takashi Iwai3c10a9d2005-08-23 20:02:27 +0200891 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
892 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
893 { } /* end */
894};
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200895
Kailang Yangdf694da2005-12-05 19:42:22 +0100896/* TCL S700 */
897static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
898 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
899 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
900 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
901 HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT),
902 HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT),
903 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT),
904 HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT),
905 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
906 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
907 {
908 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
909 /* The multiple "Capture Source" controls confuse alsamixer
910 * So call somewhat different..
911 * FIXME: the controls appear in the "playback" view!
912 */
913 /* .name = "Capture Source", */
914 .name = "Input Source",
915 .count = 1,
916 .info = alc_mux_enum_info,
917 .get = alc_mux_enum_get,
918 .put = alc_mux_enum_put,
919 },
920 { } /* end */
921};
922
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200924 * build control elements
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 */
926static int alc_build_controls(struct hda_codec *codec)
927{
928 struct alc_spec *spec = codec->spec;
929 int err;
930 int i;
931
932 for (i = 0; i < spec->num_mixers; i++) {
933 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
934 if (err < 0)
935 return err;
936 }
937
938 if (spec->multiout.dig_out_nid) {
939 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
940 if (err < 0)
941 return err;
942 }
943 if (spec->dig_in_nid) {
944 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
945 if (err < 0)
946 return err;
947 }
948 return 0;
949}
950
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200951
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952/*
953 * initialize the codec volumes, etc
954 */
955
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200956/*
957 * generic initialization of ADC, input mixers and output mixers
958 */
959static struct hda_verb alc880_volume_init_verbs[] = {
960 /*
961 * Unmute ADC0-2 and set the default input to mic-in
962 */
Takashi Iwai71fe7b82005-05-25 18:11:40 +0200963 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200964 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +0200965 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200966 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +0200967 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200968 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200970 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
971 * mixer widget
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 * Note: PASD motherboards uses the Line In 2 as the input for front panel
973 * mic (mic 2)
974 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200975 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwai16ded522005-06-10 19:58:24 +0200976 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200977 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
978 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
979 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
980 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200982 /*
983 * Set up output mixers (0x0c - 0x0f)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200985 /* set vol=0 to output mixers */
986 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
987 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
988 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
989 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
990 /* set up input amps for analog loopback */
991 /* Amp Indices: DAC = 0, mixer = 1 */
Takashi Iwai05acb862005-06-10 19:50:25 +0200992 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
993 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +0200994 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
995 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +0200996 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
997 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +0200998 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
999 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000
1001 { }
1002};
1003
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001004/*
1005 * 3-stack pin configuration:
1006 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
1007 */
1008static struct hda_verb alc880_pin_3stack_init_verbs[] = {
1009 /*
1010 * preset connection lists of input pins
1011 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
1012 */
1013 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
1014 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1015 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
1016
1017 /*
1018 * Set pin mode and muting
1019 */
1020 /* set front pin widgets 0x14 for output */
1021 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1022 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1023 /* Mic1 (rear panel) pin widget for input and vref at 80% */
1024 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1025 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1026 /* Mic2 (as headphone out) for HP output */
1027 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1028 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1029 /* Line In pin widget for input */
1030 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1031 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1032 /* Line2 (as front mic) pin widget for input and vref at 80% */
1033 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1034 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1035 /* CD pin widget for input */
1036 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1037
1038 { }
1039};
1040
1041/*
1042 * 5-stack pin configuration:
1043 * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
1044 * line-in/side = 0x1a, f-mic = 0x1b
1045 */
1046static struct hda_verb alc880_pin_5stack_init_verbs[] = {
1047 /*
1048 * preset connection lists of input pins
1049 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
1050 */
1051 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1052 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
1053
1054 /*
1055 * Set pin mode and muting
1056 */
1057 /* set pin widgets 0x14-0x17 for output */
Takashi Iwai05acb862005-06-10 19:50:25 +02001058 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1059 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1060 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1061 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001062 /* unmute pins for output (no gain on this amp) */
1063 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1064 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1065 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1066 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1067
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02001069 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001070 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1071 /* Mic2 (as headphone out) for HP output */
1072 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02001073 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001074 /* Line In pin widget for input */
1075 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1076 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1077 /* Line2 (as front mic) pin widget for input and vref at 80% */
1078 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1079 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1080 /* CD pin widget for input */
1081 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082
1083 { }
1084};
1085
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001086/*
1087 * W810 pin configuration:
1088 * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
1089 */
1090static struct hda_verb alc880_pin_w810_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 /* hphone/speaker input selector: front DAC */
1092 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
1093
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001094 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1095 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1096 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1097 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1098 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1099 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1100
1101 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02001102 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 { }
1105};
1106
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001107/*
1108 * Z71V pin configuration:
1109 * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
1110 */
1111static struct hda_verb alc880_pin_z71v_init_verbs[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02001112 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001113 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai05acb862005-06-10 19:50:25 +02001114 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001115 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001116
Takashi Iwai16ded522005-06-10 19:58:24 +02001117 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001118 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02001119 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001120 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001121
1122 { }
1123};
1124
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001125/*
1126 * 6-stack pin configuration:
1127 * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18, f-mic = 0x19,
1128 * line = 0x1a, HP = 0x1b
1129 */
1130static struct hda_verb alc880_pin_6stack_init_verbs[] = {
1131 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1132
Takashi Iwai16ded522005-06-10 19:58:24 +02001133 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001134 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001135 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001136 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001137 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001138 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001139 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001140 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1141
Takashi Iwai16ded522005-06-10 19:58:24 +02001142 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001143 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001144 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001145 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001146 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001147 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001148 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai16ded522005-06-10 19:58:24 +02001149 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001150 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1151
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001152 { }
1153};
Takashi Iwai16ded522005-06-10 19:58:24 +02001154
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001155/* FIXME! */
1156/*
1157 * F1734 pin configuration:
1158 * HP = 0x14, speaker-out = 0x15, mic = 0x18
1159 */
1160static struct hda_verb alc880_pin_f1734_init_verbs[] = {
1161 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
1162 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
1163 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
1164 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
1165
1166 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1167 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1168 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1169 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1170
1171 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1172 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1173 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1174 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1175 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1176 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1177 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1178 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1179 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02001180
1181 { }
1182};
1183
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001184/* FIXME! */
1185/*
1186 * ASUS pin configuration:
1187 * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
1188 */
1189static struct hda_verb alc880_pin_asus_init_verbs[] = {
1190 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
1191 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
1192 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
1193 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
1194
1195 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1196 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1197 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1198 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1199 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1200 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1201 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1202 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1203
1204 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1205 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1206 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1207 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1208 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1209 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1210 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1211 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1212 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1213
1214 { }
1215};
1216
1217/* Enable GPIO mask and set output */
1218static struct hda_verb alc880_gpio1_init_verbs[] = {
1219 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
1220 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
1221 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
Kailang Yangdf694da2005-12-05 19:42:22 +01001222
1223 { }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001224};
1225
1226/* Enable GPIO mask and set output */
1227static struct hda_verb alc880_gpio2_init_verbs[] = {
1228 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
1229 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
1230 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
Kailang Yangdf694da2005-12-05 19:42:22 +01001231
1232 { }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001233};
1234
Kailang Yangdf694da2005-12-05 19:42:22 +01001235/* Clevo m520g init */
1236static struct hda_verb alc880_pin_clevo_init_verbs[] = {
1237 /* headphone output */
1238 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
1239 /* line-out */
1240 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1241 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1242 /* Line-in */
1243 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1244 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1245 /* CD */
1246 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1247 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1248 /* Mic1 (rear panel) */
1249 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1250 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1251 /* Mic2 (front panel) */
1252 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1253 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1254 /* headphone */
1255 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1256 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1257 /* change to EAPD mode */
1258 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
1259 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
1260
1261 { }
1262};
1263
1264static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
1265 /* Headphone output */
1266 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1267 /* Front output*/
1268 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1269 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
1270
1271 /* Line In pin widget for input */
1272 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1273 /* CD pin widget for input */
1274 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1275 /* Mic1 (rear panel) pin widget for input and vref at 80% */
1276 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1277
1278 /* change to EAPD mode */
1279 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
1280 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
1281
1282 { }
1283};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001284
1285/*
1286 */
Takashi Iwai16ded522005-06-10 19:58:24 +02001287
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288static int alc_init(struct hda_codec *codec)
1289{
1290 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001291 unsigned int i;
1292
1293 for (i = 0; i < spec->num_init_verbs; i++)
1294 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 return 0;
1296}
1297
1298#ifdef CONFIG_PM
1299/*
1300 * resume
1301 */
1302static int alc_resume(struct hda_codec *codec)
1303{
1304 struct alc_spec *spec = codec->spec;
1305 int i;
1306
1307 alc_init(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001308 for (i = 0; i < spec->num_mixers; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 snd_hda_resume_ctls(codec, spec->mixers[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 if (spec->multiout.dig_out_nid)
1311 snd_hda_resume_spdif_out(codec);
1312 if (spec->dig_in_nid)
1313 snd_hda_resume_spdif_in(codec);
1314
1315 return 0;
1316}
1317#endif
1318
1319/*
1320 * Analog playback callbacks
1321 */
1322static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
1323 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001324 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325{
1326 struct alc_spec *spec = codec->spec;
1327 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
1328}
1329
1330static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1331 struct hda_codec *codec,
1332 unsigned int stream_tag,
1333 unsigned int format,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001334 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335{
1336 struct alc_spec *spec = codec->spec;
1337 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag,
1338 format, substream);
1339}
1340
1341static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
1342 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001343 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344{
1345 struct alc_spec *spec = codec->spec;
1346 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
1347}
1348
1349/*
1350 * Digital out
1351 */
1352static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
1353 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001354 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355{
1356 struct alc_spec *spec = codec->spec;
1357 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
1358}
1359
1360static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
1361 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001362 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363{
1364 struct alc_spec *spec = codec->spec;
1365 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
1366}
1367
1368/*
1369 * Analog capture
1370 */
1371static int alc880_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
1372 struct hda_codec *codec,
1373 unsigned int stream_tag,
1374 unsigned int format,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001375 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376{
1377 struct alc_spec *spec = codec->spec;
1378
1379 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
1380 stream_tag, 0, format);
1381 return 0;
1382}
1383
1384static int alc880_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
1385 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001386 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387{
1388 struct alc_spec *spec = codec->spec;
1389
1390 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0);
1391 return 0;
1392}
1393
1394
1395/*
1396 */
1397static struct hda_pcm_stream alc880_pcm_analog_playback = {
1398 .substreams = 1,
1399 .channels_min = 2,
1400 .channels_max = 8,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001401 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 .ops = {
1403 .open = alc880_playback_pcm_open,
1404 .prepare = alc880_playback_pcm_prepare,
1405 .cleanup = alc880_playback_pcm_cleanup
1406 },
1407};
1408
1409static struct hda_pcm_stream alc880_pcm_analog_capture = {
1410 .substreams = 2,
1411 .channels_min = 2,
1412 .channels_max = 2,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001413 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 .ops = {
1415 .prepare = alc880_capture_pcm_prepare,
1416 .cleanup = alc880_capture_pcm_cleanup
1417 },
1418};
1419
1420static struct hda_pcm_stream alc880_pcm_digital_playback = {
1421 .substreams = 1,
1422 .channels_min = 2,
1423 .channels_max = 2,
1424 /* NID is set in alc_build_pcms */
1425 .ops = {
1426 .open = alc880_dig_playback_pcm_open,
1427 .close = alc880_dig_playback_pcm_close
1428 },
1429};
1430
1431static struct hda_pcm_stream alc880_pcm_digital_capture = {
1432 .substreams = 1,
1433 .channels_min = 2,
1434 .channels_max = 2,
1435 /* NID is set in alc_build_pcms */
1436};
1437
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01001438/* Used by alc_build_pcms to flag that a PCM has no playback stream */
1439static struct hda_pcm_stream alc_pcm_null_playback = {
1440 .substreams = 0,
1441 .channels_min = 0,
1442 .channels_max = 0,
1443};
1444
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445static int alc_build_pcms(struct hda_codec *codec)
1446{
1447 struct alc_spec *spec = codec->spec;
1448 struct hda_pcm *info = spec->pcm_rec;
1449 int i;
1450
1451 codec->num_pcms = 1;
1452 codec->pcm_info = info;
1453
1454 info->name = spec->stream_name_analog;
Takashi Iwai4a471b72005-12-07 13:56:29 +01001455 if (spec->stream_analog_playback) {
1456 snd_assert(spec->multiout.dac_nids, return -EINVAL);
1457 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
1458 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
1459 }
1460 if (spec->stream_analog_capture) {
1461 snd_assert(spec->adc_nids, return -EINVAL);
1462 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
1463 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
1464 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465
Takashi Iwai4a471b72005-12-07 13:56:29 +01001466 if (spec->channel_mode) {
1467 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
1468 for (i = 0; i < spec->num_channel_mode; i++) {
1469 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
1470 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
1471 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 }
1473 }
1474
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01001475 /* If the use of more than one ADC is requested for the current
1476 * model, configure a second analog capture-only PCM.
1477 */
1478 if (spec->num_adc_nids > 1) {
1479 codec->num_pcms++;
1480 info++;
1481 info->name = spec->stream_name_analog;
1482 /* No playback stream for second PCM */
1483 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = alc_pcm_null_playback;
1484 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
1485 if (spec->stream_analog_capture) {
1486 snd_assert(spec->adc_nids, return -EINVAL);
1487 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
1488 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[1];
1489 }
1490 }
1491
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
1493 codec->num_pcms++;
1494 info++;
1495 info->name = spec->stream_name_digital;
Takashi Iwai4a471b72005-12-07 13:56:29 +01001496 if (spec->multiout.dig_out_nid &&
1497 spec->stream_digital_playback) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
1499 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
1500 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01001501 if (spec->dig_in_nid &&
1502 spec->stream_digital_capture) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
1504 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
1505 }
1506 }
1507
1508 return 0;
1509}
1510
1511static void alc_free(struct hda_codec *codec)
1512{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001513 struct alc_spec *spec = codec->spec;
1514 unsigned int i;
1515
1516 if (! spec)
1517 return;
1518
1519 if (spec->kctl_alloc) {
1520 for (i = 0; i < spec->num_kctl_used; i++)
1521 kfree(spec->kctl_alloc[i].name);
1522 kfree(spec->kctl_alloc);
1523 }
1524 kfree(spec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525}
1526
1527/*
1528 */
1529static struct hda_codec_ops alc_patch_ops = {
1530 .build_controls = alc_build_controls,
1531 .build_pcms = alc_build_pcms,
1532 .init = alc_init,
1533 .free = alc_free,
1534#ifdef CONFIG_PM
1535 .resume = alc_resume,
1536#endif
1537};
1538
Takashi Iwai2fa522b2005-05-12 14:51:12 +02001539
1540/*
1541 * Test configuration for debugging
1542 *
1543 * Almost all inputs/outputs are enabled. I/O pins can be configured via
1544 * enum controls.
1545 */
1546#ifdef CONFIG_SND_DEBUG
1547static hda_nid_t alc880_test_dac_nids[4] = {
1548 0x02, 0x03, 0x04, 0x05
1549};
1550
1551static struct hda_input_mux alc880_test_capture_source = {
1552 .num_items = 5,
1553 .items = {
1554 { "In-1", 0x0 },
1555 { "In-2", 0x1 },
1556 { "In-3", 0x2 },
1557 { "In-4", 0x3 },
1558 { "CD", 0x4 },
1559 },
1560};
1561
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001562static struct hda_channel_mode alc880_test_modes[4] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02001563 { 2, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02001564 { 4, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02001565 { 6, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02001566 { 8, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02001567};
1568
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001569static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02001570{
1571 static char *texts[] = {
1572 "N/A", "Line Out", "HP Out",
1573 "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
1574 };
1575 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1576 uinfo->count = 1;
1577 uinfo->value.enumerated.items = 8;
1578 if (uinfo->value.enumerated.item >= 8)
1579 uinfo->value.enumerated.item = 7;
1580 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1581 return 0;
1582}
1583
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001584static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02001585{
1586 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1587 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
1588 unsigned int pin_ctl, item = 0;
1589
1590 pin_ctl = snd_hda_codec_read(codec, nid, 0,
1591 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
1592 if (pin_ctl & AC_PINCTL_OUT_EN) {
1593 if (pin_ctl & AC_PINCTL_HP_EN)
1594 item = 2;
1595 else
1596 item = 1;
1597 } else if (pin_ctl & AC_PINCTL_IN_EN) {
1598 switch (pin_ctl & AC_PINCTL_VREFEN) {
1599 case AC_PINCTL_VREF_HIZ: item = 3; break;
1600 case AC_PINCTL_VREF_50: item = 4; break;
1601 case AC_PINCTL_VREF_GRD: item = 5; break;
1602 case AC_PINCTL_VREF_80: item = 6; break;
1603 case AC_PINCTL_VREF_100: item = 7; break;
1604 }
1605 }
1606 ucontrol->value.enumerated.item[0] = item;
1607 return 0;
1608}
1609
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001610static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02001611{
1612 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1613 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
1614 static unsigned int ctls[] = {
1615 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
1616 AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
1617 AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
1618 AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
1619 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
1620 AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
1621 };
1622 unsigned int old_ctl, new_ctl;
1623
1624 old_ctl = snd_hda_codec_read(codec, nid, 0,
1625 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
1626 new_ctl = ctls[ucontrol->value.enumerated.item[0]];
1627 if (old_ctl != new_ctl) {
1628 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, new_ctl);
1629 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
1630 ucontrol->value.enumerated.item[0] >= 3 ? 0xb080 : 0xb000);
1631 return 1;
1632 }
1633 return 0;
1634}
1635
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001636static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02001637{
1638 static char *texts[] = {
1639 "Front", "Surround", "CLFE", "Side"
1640 };
1641 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1642 uinfo->count = 1;
1643 uinfo->value.enumerated.items = 4;
1644 if (uinfo->value.enumerated.item >= 4)
1645 uinfo->value.enumerated.item = 3;
1646 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1647 return 0;
1648}
1649
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001650static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02001651{
1652 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1653 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
1654 unsigned int sel;
1655
1656 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
1657 ucontrol->value.enumerated.item[0] = sel & 3;
1658 return 0;
1659}
1660
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001661static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02001662{
1663 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1664 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
1665 unsigned int sel;
1666
1667 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
1668 if (ucontrol->value.enumerated.item[0] != sel) {
1669 sel = ucontrol->value.enumerated.item[0] & 3;
1670 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, sel);
1671 return 1;
1672 }
1673 return 0;
1674}
1675
1676#define PIN_CTL_TEST(xname,nid) { \
1677 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1678 .name = xname, \
1679 .info = alc_test_pin_ctl_info, \
1680 .get = alc_test_pin_ctl_get, \
1681 .put = alc_test_pin_ctl_put, \
1682 .private_value = nid \
1683 }
1684
1685#define PIN_SRC_TEST(xname,nid) { \
1686 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1687 .name = xname, \
1688 .info = alc_test_pin_src_info, \
1689 .get = alc_test_pin_src_get, \
1690 .put = alc_test_pin_src_put, \
1691 .private_value = nid \
1692 }
1693
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001694static struct snd_kcontrol_new alc880_test_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02001695 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1696 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1697 HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
1698 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001699 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
1700 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
1701 HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
1702 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02001703 PIN_CTL_TEST("Front Pin Mode", 0x14),
1704 PIN_CTL_TEST("Surround Pin Mode", 0x15),
1705 PIN_CTL_TEST("CLFE Pin Mode", 0x16),
1706 PIN_CTL_TEST("Side Pin Mode", 0x17),
1707 PIN_CTL_TEST("In-1 Pin Mode", 0x18),
1708 PIN_CTL_TEST("In-2 Pin Mode", 0x19),
1709 PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
1710 PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
1711 PIN_SRC_TEST("In-1 Pin Source", 0x18),
1712 PIN_SRC_TEST("In-2 Pin Source", 0x19),
1713 PIN_SRC_TEST("In-3 Pin Source", 0x1a),
1714 PIN_SRC_TEST("In-4 Pin Source", 0x1b),
1715 HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
1716 HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
1717 HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
1718 HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
1719 HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
1720 HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
1721 HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
1722 HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
1723 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
1724 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02001725 {
1726 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1727 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001728 .info = alc_ch_mode_info,
1729 .get = alc_ch_mode_get,
1730 .put = alc_ch_mode_put,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02001731 },
1732 { } /* end */
1733};
1734
1735static struct hda_verb alc880_test_init_verbs[] = {
1736 /* Unmute inputs of 0x0c - 0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02001737 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1738 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1739 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1740 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1741 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1742 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
1743 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1744 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02001745 /* Vol output for 0x0c-0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02001746 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1747 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1748 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1749 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02001750 /* Set output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02001751 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1752 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1753 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1754 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02001755 /* Unmute output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02001756 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1757 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1758 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1759 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02001760 /* Set input pins 0x18-0x1c */
Takashi Iwai16ded522005-06-10 19:58:24 +02001761 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1762 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai05acb862005-06-10 19:50:25 +02001763 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1764 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1765 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02001766 /* Mute input pins 0x18-0x1b */
Takashi Iwai05acb862005-06-10 19:50:25 +02001767 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1768 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1769 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1770 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001771 /* ADC set up */
Takashi Iwai05acb862005-06-10 19:50:25 +02001772 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001773 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02001774 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001775 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02001776 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001777 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02001778 /* Analog input/passthru */
1779 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1780 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1781 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
1782 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
1783 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02001784 { }
1785};
1786#endif
1787
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788/*
1789 */
1790
1791static struct hda_board_config alc880_cfg_tbl[] = {
1792 /* Back 3 jack, front 2 jack */
1793 { .modelname = "3stack", .config = ALC880_3ST },
Takashi Iwai72915482005-05-12 16:49:45 +02001794 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe200, .config = ALC880_3ST },
1795 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe201, .config = ALC880_3ST },
1796 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe202, .config = ALC880_3ST },
1797 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe203, .config = ALC880_3ST },
1798 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe204, .config = ALC880_3ST },
1799 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe205, .config = ALC880_3ST },
1800 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe206, .config = ALC880_3ST },
1801 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe207, .config = ALC880_3ST },
1802 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe208, .config = ALC880_3ST },
1803 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe209, .config = ALC880_3ST },
1804 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20a, .config = ALC880_3ST },
1805 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20b, .config = ALC880_3ST },
1806 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20c, .config = ALC880_3ST },
1807 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20d, .config = ALC880_3ST },
1808 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20e, .config = ALC880_3ST },
1809 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20f, .config = ALC880_3ST },
1810 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe210, .config = ALC880_3ST },
1811 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe211, .config = ALC880_3ST },
1812 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe214, .config = ALC880_3ST },
1813 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe302, .config = ALC880_3ST },
1814 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe303, .config = ALC880_3ST },
1815 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe304, .config = ALC880_3ST },
1816 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe306, .config = ALC880_3ST },
1817 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe307, .config = ALC880_3ST },
1818 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe404, .config = ALC880_3ST },
1819 { .pci_subvendor = 0x8086, .pci_subdevice = 0xa101, .config = ALC880_3ST },
1820 { .pci_subvendor = 0x107b, .pci_subdevice = 0x3031, .config = ALC880_3ST },
1821 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4036, .config = ALC880_3ST },
1822 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4037, .config = ALC880_3ST },
1823 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4038, .config = ALC880_3ST },
1824 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4040, .config = ALC880_3ST },
1825 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4041, .config = ALC880_3ST },
Kailang Yangdf694da2005-12-05 19:42:22 +01001826 /* TCL S700 */
1827 { .pci_subvendor = 0x19db, .pci_subdevice = 0x4188, .config = ALC880_TCL_S700 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828
1829 /* Back 3 jack, front 2 jack (Internal add Aux-In) */
Takashi Iwai72915482005-05-12 16:49:45 +02001830 { .pci_subvendor = 0x1025, .pci_subdevice = 0xe310, .config = ALC880_3ST },
Takashi Iwai16ded522005-06-10 19:58:24 +02001831 { .pci_subvendor = 0x104d, .pci_subdevice = 0x81d6, .config = ALC880_3ST },
Davide Libenzi0ca21612005-09-05 11:56:47 +02001832 { .pci_subvendor = 0x104d, .pci_subdevice = 0x81a0, .config = ALC880_3ST },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833
1834 /* Back 3 jack plus 1 SPDIF out jack, front 2 jack */
1835 { .modelname = "3stack-digout", .config = ALC880_3ST_DIG },
Takashi Iwai72915482005-05-12 16:49:45 +02001836 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe308, .config = ALC880_3ST_DIG },
Jaroslav Kysela5a47fe32005-08-15 20:01:40 +02001837 { .pci_subvendor = 0x1025, .pci_subdevice = 0x0070, .config = ALC880_3ST_DIG },
Kailang Yangdf694da2005-12-05 19:42:22 +01001838 /* Clevo m520G NB */
1839 { .pci_subvendor = 0x1558, .pci_subdevice = 0x0520, .config = ALC880_CLEVO },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840
1841 /* Back 3 jack plus 1 SPDIF out jack, front 2 jack (Internal add Aux-In)*/
Takashi Iwai72915482005-05-12 16:49:45 +02001842 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe305, .config = ALC880_3ST_DIG },
1843 { .pci_subvendor = 0x8086, .pci_subdevice = 0xd402, .config = ALC880_3ST_DIG },
1844 { .pci_subvendor = 0x1025, .pci_subdevice = 0xe309, .config = ALC880_3ST_DIG },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845
1846 /* Back 5 jack, front 2 jack */
1847 { .modelname = "5stack", .config = ALC880_5ST },
Takashi Iwai72915482005-05-12 16:49:45 +02001848 { .pci_subvendor = 0x107b, .pci_subdevice = 0x3033, .config = ALC880_5ST },
1849 { .pci_subvendor = 0x107b, .pci_subdevice = 0x4039, .config = ALC880_5ST },
1850 { .pci_subvendor = 0x107b, .pci_subdevice = 0x3032, .config = ALC880_5ST },
1851 { .pci_subvendor = 0x103c, .pci_subdevice = 0x2a09, .config = ALC880_5ST },
Takashi Iwai16ded522005-06-10 19:58:24 +02001852 { .pci_subvendor = 0x1043, .pci_subdevice = 0x814e, .config = ALC880_5ST },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853
1854 /* Back 5 jack plus 1 SPDIF out jack, front 2 jack */
1855 { .modelname = "5stack-digout", .config = ALC880_5ST_DIG },
Takashi Iwai72915482005-05-12 16:49:45 +02001856 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe224, .config = ALC880_5ST_DIG },
1857 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe400, .config = ALC880_5ST_DIG },
1858 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe401, .config = ALC880_5ST_DIG },
1859 { .pci_subvendor = 0x8086, .pci_subdevice = 0xe402, .config = ALC880_5ST_DIG },
1860 { .pci_subvendor = 0x8086, .pci_subdevice = 0xd400, .config = ALC880_5ST_DIG },
1861 { .pci_subvendor = 0x8086, .pci_subdevice = 0xd401, .config = ALC880_5ST_DIG },
1862 { .pci_subvendor = 0x8086, .pci_subdevice = 0xa100, .config = ALC880_5ST_DIG },
1863 { .pci_subvendor = 0x1565, .pci_subdevice = 0x8202, .config = ALC880_5ST_DIG },
Takashi Iwai16ded522005-06-10 19:58:24 +02001864 { .pci_subvendor = 0x1019, .pci_subdevice = 0xa880, .config = ALC880_5ST_DIG },
Takashi Iwai7a318a72005-06-28 14:16:21 +02001865 /* { .pci_subvendor = 0x1019, .pci_subdevice = 0xa884, .config = ALC880_5ST_DIG }, */ /* conflict with 6stack */
Takashi Iwai16ded522005-06-10 19:58:24 +02001866 { .pci_subvendor = 0x1695, .pci_subdevice = 0x400d, .config = ALC880_5ST_DIG },
Takashi Iwaib0af0de2005-06-21 14:49:19 +02001867 /* note subvendor = 0 below */
1868 /* { .pci_subvendor = 0x0000, .pci_subdevice = 0x8086, .config = ALC880_5ST_DIG }, */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869
1870 { .modelname = "w810", .config = ALC880_W810 },
Takashi Iwai72915482005-05-12 16:49:45 +02001871 { .pci_subvendor = 0x161f, .pci_subdevice = 0x203d, .config = ALC880_W810 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001873 { .modelname = "z71v", .config = ALC880_Z71V },
Takashi Iwai72915482005-05-12 16:49:45 +02001874 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_Z71V },
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001875
Takashi Iwaib6482d42005-06-27 15:32:43 +02001876 { .modelname = "6stack", .config = ALC880_6ST },
Takashi Iwai7632c7b2005-12-07 18:25:47 +01001877 { .pci_subvendor = 0x1043, .pci_subdevice = 0x8196, .config = ALC880_6ST }, /* ASUS P5GD1-HVM */
Kailang Yangdf694da2005-12-05 19:42:22 +01001878 { .pci_subvendor = 0x1043, .pci_subdevice = 0x81b4, .config = ALC880_6ST },
Takashi Iwai7a318a72005-06-28 14:16:21 +02001879 { .pci_subvendor = 0x1019, .pci_subdevice = 0xa884, .config = ALC880_6ST }, /* Acer APFV */
Arnaud Patardbae2bdb2006-01-27 12:05:02 +01001880 { .pci_subvendor = 0x1458, .pci_subdevice = 0xa102, .config = ALC880_6ST }, /* Gigabyte K8N51 */
Takashi Iwaib6482d42005-06-27 15:32:43 +02001881
1882 { .modelname = "6stack-digout", .config = ALC880_6ST_DIG },
Takashi Iwai16ded522005-06-10 19:58:24 +02001883 { .pci_subvendor = 0x2668, .pci_subdevice = 0x8086, .config = ALC880_6ST_DIG },
1884 { .pci_subvendor = 0x8086, .pci_subdevice = 0x2668, .config = ALC880_6ST_DIG },
1885 { .pci_subvendor = 0x1462, .pci_subdevice = 0x1150, .config = ALC880_6ST_DIG },
1886 { .pci_subvendor = 0xe803, .pci_subdevice = 0x1019, .config = ALC880_6ST_DIG },
Kailang Yangdf694da2005-12-05 19:42:22 +01001887 { .pci_subvendor = 0x1039, .pci_subdevice = 0x1234, .config = ALC880_6ST_DIG },
1888 { .pci_subvendor = 0x1025, .pci_subdevice = 0x0077, .config = ALC880_6ST_DIG },
1889 { .pci_subvendor = 0x1025, .pci_subdevice = 0x0078, .config = ALC880_6ST_DIG },
1890 { .pci_subvendor = 0x1025, .pci_subdevice = 0x0087, .config = ALC880_6ST_DIG },
Takashi Iwai041dec02005-12-23 12:27:52 +01001891 { .pci_subvendor = 0x1297, .pci_subdevice = 0xc790, .config = ALC880_6ST_DIG }, /* Shuttle ST20G5 */
Takashi Iwai16ded522005-06-10 19:58:24 +02001892
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001893 { .modelname = "asus", .config = ALC880_ASUS },
Takashi Iwai16ded522005-06-10 19:58:24 +02001894 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_ASUS_DIG },
1895 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1973, .config = ALC880_ASUS_DIG },
1896 { .pci_subvendor = 0x1043, .pci_subdevice = 0x19b3, .config = ALC880_ASUS_DIG },
1897 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1113, .config = ALC880_ASUS_DIG },
Takashi Iwai86488112005-09-09 13:56:32 +02001898 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1173, .config = ALC880_ASUS_DIG },
Takashi Iwai16ded522005-06-10 19:58:24 +02001899 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1993, .config = ALC880_ASUS },
1900 { .pci_subvendor = 0x1043, .pci_subdevice = 0x10c3, .config = ALC880_ASUS_DIG },
1901 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1133, .config = ALC880_ASUS },
1902 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1123, .config = ALC880_ASUS_DIG },
1903 { .pci_subvendor = 0x1043, .pci_subdevice = 0x1143, .config = ALC880_ASUS },
1904 { .pci_subvendor = 0x1043, .pci_subdevice = 0x10b3, .config = ALC880_ASUS_W1V },
Kailang Yangdf694da2005-12-05 19:42:22 +01001905 { .pci_subvendor = 0x1558, .pci_subdevice = 0x5401, .config = ALC880_ASUS_DIG2 },
Takashi Iwai16ded522005-06-10 19:58:24 +02001906
1907 { .modelname = "uniwill", .config = ALC880_UNIWILL_DIG },
1908 { .pci_subvendor = 0x1584, .pci_subdevice = 0x9050, .config = ALC880_UNIWILL_DIG },
1909
1910 { .modelname = "F1734", .config = ALC880_F1734 },
1911 { .pci_subvendor = 0x1734, .pci_subdevice = 0x107c, .config = ALC880_F1734 },
Kailang Yangdf694da2005-12-05 19:42:22 +01001912 { .pci_subvendor = 0x1584, .pci_subdevice = 0x9054, .config = ALC880_F1734 },
Takashi Iwai16ded522005-06-10 19:58:24 +02001913
Takashi Iwai2fa522b2005-05-12 14:51:12 +02001914#ifdef CONFIG_SND_DEBUG
1915 { .modelname = "test", .config = ALC880_TEST },
1916#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01001917 { .modelname = "auto", .config = ALC880_AUTO },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02001918
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 {}
1920};
1921
Takashi Iwai16ded522005-06-10 19:58:24 +02001922/*
Kailang Yangdf694da2005-12-05 19:42:22 +01001923 * ALC880 codec presets
Takashi Iwai16ded522005-06-10 19:58:24 +02001924 */
Takashi Iwai16ded522005-06-10 19:58:24 +02001925static struct alc_config_preset alc880_presets[] = {
1926 [ALC880_3ST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001927 .mixers = { alc880_three_stack_mixer },
1928 .init_verbs = { alc880_volume_init_verbs, alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02001929 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02001930 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02001931 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
1932 .channel_mode = alc880_threestack_modes,
1933 .input_mux = &alc880_capture_source,
1934 },
1935 [ALC880_3ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001936 .mixers = { alc880_three_stack_mixer },
1937 .init_verbs = { alc880_volume_init_verbs, alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02001938 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02001939 .dac_nids = alc880_dac_nids,
1940 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02001941 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
1942 .channel_mode = alc880_threestack_modes,
1943 .input_mux = &alc880_capture_source,
1944 },
Kailang Yangdf694da2005-12-05 19:42:22 +01001945 [ALC880_TCL_S700] = {
1946 .mixers = { alc880_tcl_s700_mixer },
1947 .init_verbs = { alc880_volume_init_verbs,
1948 alc880_pin_tcl_S700_init_verbs,
1949 alc880_gpio2_init_verbs },
1950 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
1951 .dac_nids = alc880_dac_nids,
1952 .hp_nid = 0x03,
1953 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
1954 .channel_mode = alc880_2_jack_modes,
1955 .input_mux = &alc880_capture_source,
1956 },
Takashi Iwai16ded522005-06-10 19:58:24 +02001957 [ALC880_5ST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001958 .mixers = { alc880_three_stack_mixer, alc880_five_stack_mixer},
1959 .init_verbs = { alc880_volume_init_verbs, alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02001960 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
1961 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02001962 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
1963 .channel_mode = alc880_fivestack_modes,
1964 .input_mux = &alc880_capture_source,
1965 },
1966 [ALC880_5ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001967 .mixers = { alc880_three_stack_mixer, alc880_five_stack_mixer },
1968 .init_verbs = { alc880_volume_init_verbs, alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02001969 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
1970 .dac_nids = alc880_dac_nids,
1971 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02001972 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
1973 .channel_mode = alc880_fivestack_modes,
1974 .input_mux = &alc880_capture_source,
1975 },
Takashi Iwaib6482d42005-06-27 15:32:43 +02001976 [ALC880_6ST] = {
1977 .mixers = { alc880_six_stack_mixer },
1978 .init_verbs = { alc880_volume_init_verbs, alc880_pin_6stack_init_verbs },
1979 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
1980 .dac_nids = alc880_6st_dac_nids,
1981 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
1982 .channel_mode = alc880_sixstack_modes,
1983 .input_mux = &alc880_6stack_capture_source,
1984 },
Takashi Iwai16ded522005-06-10 19:58:24 +02001985 [ALC880_6ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001986 .mixers = { alc880_six_stack_mixer },
1987 .init_verbs = { alc880_volume_init_verbs, alc880_pin_6stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02001988 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
1989 .dac_nids = alc880_6st_dac_nids,
1990 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02001991 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
1992 .channel_mode = alc880_sixstack_modes,
1993 .input_mux = &alc880_6stack_capture_source,
1994 },
1995 [ALC880_W810] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001996 .mixers = { alc880_w810_base_mixer },
Takashi Iwaib0af0de2005-06-21 14:49:19 +02001997 .init_verbs = { alc880_volume_init_verbs, alc880_pin_w810_init_verbs,
1998 alc880_gpio2_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02001999 .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
2000 .dac_nids = alc880_w810_dac_nids,
2001 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02002002 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
2003 .channel_mode = alc880_w810_modes,
2004 .input_mux = &alc880_capture_source,
2005 },
2006 [ALC880_Z71V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002007 .mixers = { alc880_z71v_mixer },
Takashi Iwaib0af0de2005-06-21 14:49:19 +02002008 .init_verbs = { alc880_volume_init_verbs, alc880_pin_z71v_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02002009 .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
2010 .dac_nids = alc880_z71v_dac_nids,
2011 .dig_out_nid = ALC880_DIGOUT_NID,
2012 .hp_nid = 0x03,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002013 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
2014 .channel_mode = alc880_2_jack_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02002015 .input_mux = &alc880_capture_source,
2016 },
2017 [ALC880_F1734] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002018 .mixers = { alc880_f1734_mixer },
2019 .init_verbs = { alc880_volume_init_verbs, alc880_pin_f1734_init_verbs },
2020 .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
2021 .dac_nids = alc880_f1734_dac_nids,
2022 .hp_nid = 0x02,
2023 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
2024 .channel_mode = alc880_2_jack_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02002025 .input_mux = &alc880_capture_source,
2026 },
2027 [ALC880_ASUS] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002028 .mixers = { alc880_asus_mixer },
2029 .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs,
2030 alc880_gpio1_init_verbs },
2031 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
2032 .dac_nids = alc880_asus_dac_nids,
2033 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
2034 .channel_mode = alc880_asus_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02002035 .input_mux = &alc880_capture_source,
2036 },
2037 [ALC880_ASUS_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002038 .mixers = { alc880_asus_mixer },
2039 .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs,
2040 alc880_gpio1_init_verbs },
2041 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
2042 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02002043 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002044 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
2045 .channel_mode = alc880_asus_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02002046 .input_mux = &alc880_capture_source,
2047 },
Kailang Yangdf694da2005-12-05 19:42:22 +01002048 [ALC880_ASUS_DIG2] = {
2049 .mixers = { alc880_asus_mixer },
2050 .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs,
2051 alc880_gpio2_init_verbs }, /* use GPIO2 */
2052 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
2053 .dac_nids = alc880_asus_dac_nids,
2054 .dig_out_nid = ALC880_DIGOUT_NID,
2055 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
2056 .channel_mode = alc880_asus_modes,
2057 .input_mux = &alc880_capture_source,
2058 },
Takashi Iwai16ded522005-06-10 19:58:24 +02002059 [ALC880_ASUS_W1V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002060 .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer },
2061 .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs,
2062 alc880_gpio1_init_verbs },
2063 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
2064 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02002065 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002066 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
2067 .channel_mode = alc880_asus_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02002068 .input_mux = &alc880_capture_source,
2069 },
2070 [ALC880_UNIWILL_DIG] = {
Takashi Iwai3c10a9d2005-08-23 20:02:27 +02002071 .mixers = { alc880_asus_mixer, alc880_pcbeep_mixer },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002072 .init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs },
2073 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
2074 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02002075 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002076 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
2077 .channel_mode = alc880_asus_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02002078 .input_mux = &alc880_capture_source,
2079 },
Kailang Yangdf694da2005-12-05 19:42:22 +01002080 [ALC880_CLEVO] = {
2081 .mixers = { alc880_three_stack_mixer },
2082 .init_verbs = { alc880_volume_init_verbs,
2083 alc880_pin_clevo_init_verbs },
2084 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
2085 .dac_nids = alc880_dac_nids,
2086 .hp_nid = 0x03,
2087 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
2088 .channel_mode = alc880_threestack_modes,
2089 .input_mux = &alc880_capture_source,
2090 },
Takashi Iwai16ded522005-06-10 19:58:24 +02002091#ifdef CONFIG_SND_DEBUG
2092 [ALC880_TEST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002093 .mixers = { alc880_test_mixer },
2094 .init_verbs = { alc880_test_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02002095 .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
2096 .dac_nids = alc880_test_dac_nids,
2097 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02002098 .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
2099 .channel_mode = alc880_test_modes,
2100 .input_mux = &alc880_test_capture_source,
2101 },
2102#endif
2103};
2104
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002105/*
2106 * Automatic parse of I/O pins from the BIOS configuration
2107 */
2108
2109#define NUM_CONTROL_ALLOC 32
2110#define NUM_VERB_ALLOC 32
2111
2112enum {
2113 ALC_CTL_WIDGET_VOL,
2114 ALC_CTL_WIDGET_MUTE,
2115 ALC_CTL_BIND_MUTE,
2116};
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002117static struct snd_kcontrol_new alc880_control_templates[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002118 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
2119 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Takashi Iwai985be542005-11-02 18:26:49 +01002120 HDA_BIND_MUTE(NULL, 0, 0, 0),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002121};
2122
2123/* add dynamic controls */
2124static int add_control(struct alc_spec *spec, int type, const char *name, unsigned long val)
2125{
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002126 struct snd_kcontrol_new *knew;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002127
2128 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
2129 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
2130
2131 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */
2132 if (! knew)
2133 return -ENOMEM;
2134 if (spec->kctl_alloc) {
2135 memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc);
2136 kfree(spec->kctl_alloc);
2137 }
2138 spec->kctl_alloc = knew;
2139 spec->num_kctl_alloc = num;
2140 }
2141
2142 knew = &spec->kctl_alloc[spec->num_kctl_used];
2143 *knew = alc880_control_templates[type];
Paulo Marques543537b2005-06-23 00:09:02 -07002144 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002145 if (! knew->name)
2146 return -ENOMEM;
2147 knew->private_value = val;
2148 spec->num_kctl_used++;
2149 return 0;
2150}
2151
2152#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
2153#define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
2154#define alc880_is_multi_pin(nid) ((nid) >= 0x18)
2155#define alc880_multi_pin_idx(nid) ((nid) - 0x18)
2156#define alc880_is_input_pin(nid) ((nid) >= 0x18)
2157#define alc880_input_pin_idx(nid) ((nid) - 0x18)
2158#define alc880_idx_to_dac(nid) ((nid) + 0x02)
2159#define alc880_dac_to_idx(nid) ((nid) - 0x02)
2160#define alc880_idx_to_mixer(nid) ((nid) + 0x0c)
2161#define alc880_idx_to_selector(nid) ((nid) + 0x10)
2162#define ALC880_PIN_CD_NID 0x1c
2163
2164/* fill in the dac_nids table from the parsed pin configuration */
2165static int alc880_auto_fill_dac_nids(struct alc_spec *spec, const struct auto_pin_cfg *cfg)
2166{
2167 hda_nid_t nid;
2168 int assigned[4];
2169 int i, j;
2170
2171 memset(assigned, 0, sizeof(assigned));
Takashi Iwaib0af0de2005-06-21 14:49:19 +02002172 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002173
2174 /* check the pins hardwired to audio widget */
2175 for (i = 0; i < cfg->line_outs; i++) {
2176 nid = cfg->line_out_pins[i];
2177 if (alc880_is_fixed_pin(nid)) {
2178 int idx = alc880_fixed_pin_idx(nid);
Libin Yang5014f192005-11-23 15:48:36 +01002179 spec->multiout.dac_nids[i] = alc880_idx_to_dac(idx);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002180 assigned[idx] = 1;
2181 }
2182 }
2183 /* left pins can be connect to any audio widget */
2184 for (i = 0; i < cfg->line_outs; i++) {
2185 nid = cfg->line_out_pins[i];
2186 if (alc880_is_fixed_pin(nid))
2187 continue;
2188 /* search for an empty channel */
2189 for (j = 0; j < cfg->line_outs; j++) {
2190 if (! assigned[j]) {
2191 spec->multiout.dac_nids[i] = alc880_idx_to_dac(j);
2192 assigned[j] = 1;
2193 break;
2194 }
2195 }
2196 }
2197 spec->multiout.num_dacs = cfg->line_outs;
2198 return 0;
2199}
2200
2201/* add playback controls from the parsed DAC table */
Kailang Yangdf694da2005-12-05 19:42:22 +01002202static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
2203 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002204{
2205 char name[32];
2206 static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" };
2207 hda_nid_t nid;
2208 int i, err;
2209
2210 for (i = 0; i < cfg->line_outs; i++) {
2211 if (! spec->multiout.dac_nids[i])
2212 continue;
2213 nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
2214 if (i == 2) {
2215 /* Center/LFE */
2216 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Center Playback Volume",
2217 HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT))) < 0)
2218 return err;
2219 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "LFE Playback Volume",
2220 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0)
2221 return err;
2222 if ((err = add_control(spec, ALC_CTL_BIND_MUTE, "Center Playback Switch",
2223 HDA_COMPOSE_AMP_VAL(nid, 1, 2, HDA_INPUT))) < 0)
2224 return err;
2225 if ((err = add_control(spec, ALC_CTL_BIND_MUTE, "LFE Playback Switch",
2226 HDA_COMPOSE_AMP_VAL(nid, 2, 2, HDA_INPUT))) < 0)
2227 return err;
2228 } else {
2229 sprintf(name, "%s Playback Volume", chname[i]);
2230 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
2231 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
2232 return err;
2233 sprintf(name, "%s Playback Switch", chname[i]);
2234 if ((err = add_control(spec, ALC_CTL_BIND_MUTE, name,
2235 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT))) < 0)
2236 return err;
2237 }
2238 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002239 return 0;
2240}
2241
Takashi Iwai8d88bc32005-11-17 11:09:23 +01002242/* add playback controls for speaker and HP outputs */
2243static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
2244 const char *pfx)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002245{
2246 hda_nid_t nid;
2247 int err;
Takashi Iwai8d88bc32005-11-17 11:09:23 +01002248 char name[32];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002249
2250 if (! pin)
2251 return 0;
2252
2253 if (alc880_is_fixed_pin(pin)) {
2254 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
2255 if (! spec->multiout.dac_nids[0]) {
2256 /* use this as the primary output */
2257 spec->multiout.dac_nids[0] = nid;
2258 if (! spec->multiout.num_dacs)
2259 spec->multiout.num_dacs = 1;
2260 } else
Takashi Iwai8d88bc32005-11-17 11:09:23 +01002261 /* specify the DAC as the extra output */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002262 spec->multiout.hp_nid = nid;
2263 /* control HP volume/switch on the output mixer amp */
2264 nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
Takashi Iwai8d88bc32005-11-17 11:09:23 +01002265 sprintf(name, "%s Playback Volume", pfx);
2266 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002267 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
2268 return err;
Takashi Iwai8d88bc32005-11-17 11:09:23 +01002269 sprintf(name, "%s Playback Switch", pfx);
2270 if ((err = add_control(spec, ALC_CTL_BIND_MUTE, name,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002271 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT))) < 0)
2272 return err;
2273 } else if (alc880_is_multi_pin(pin)) {
2274 /* set manual connection */
2275 if (! spec->multiout.dac_nids[0]) {
2276 /* use this as the primary output */
2277 spec->multiout.dac_nids[0] = alc880_idx_to_dac(alc880_multi_pin_idx(pin));
2278 if (! spec->multiout.num_dacs)
2279 spec->multiout.num_dacs = 1;
2280 }
2281 /* we have only a switch on HP-out PIN */
Takashi Iwai8d88bc32005-11-17 11:09:23 +01002282 sprintf(name, "%s Playback Switch", pfx);
2283 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002284 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT))) < 0)
2285 return err;
2286 }
2287 return 0;
2288}
2289
2290/* create input playback/capture controls for the given pin */
Kailang Yangdf694da2005-12-05 19:42:22 +01002291static int new_analog_input(struct alc_spec *spec, hda_nid_t pin, const char *ctlname,
2292 int idx, hda_nid_t mix_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002293{
2294 char name[32];
Kailang Yangdf694da2005-12-05 19:42:22 +01002295 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002296
2297 sprintf(name, "%s Playback Volume", ctlname);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002298 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
Kailang Yangdf694da2005-12-05 19:42:22 +01002299 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT))) < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002300 return err;
2301 sprintf(name, "%s Playback Switch", ctlname);
2302 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
Kailang Yangdf694da2005-12-05 19:42:22 +01002303 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT))) < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002304 return err;
2305 return 0;
2306}
2307
2308/* create playback/capture controls for input pins */
Kailang Yangdf694da2005-12-05 19:42:22 +01002309static int alc880_auto_create_analog_input_ctls(struct alc_spec *spec,
2310 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002311{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002312 struct hda_input_mux *imux = &spec->private_imux;
Kailang Yangdf694da2005-12-05 19:42:22 +01002313 int i, err, idx;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002314
2315 for (i = 0; i < AUTO_PIN_LAST; i++) {
2316 if (alc880_is_input_pin(cfg->input_pins[i])) {
Kailang Yangdf694da2005-12-05 19:42:22 +01002317 idx = alc880_input_pin_idx(cfg->input_pins[i]);
Takashi Iwai4a471b72005-12-07 13:56:29 +01002318 err = new_analog_input(spec, cfg->input_pins[i],
2319 auto_pin_cfg_labels[i],
Kailang Yangdf694da2005-12-05 19:42:22 +01002320 idx, 0x0b);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002321 if (err < 0)
2322 return err;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002323 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002324 imux->items[imux->num_items].index = alc880_input_pin_idx(cfg->input_pins[i]);
2325 imux->num_items++;
2326 }
2327 }
2328 return 0;
2329}
2330
Kailang Yangdf694da2005-12-05 19:42:22 +01002331static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
2332 hda_nid_t nid, int pin_type,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002333 int dac_idx)
2334{
2335 /* set as output */
2336 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
2337 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
2338 /* need the manual connection? */
2339 if (alc880_is_multi_pin(nid)) {
2340 struct alc_spec *spec = codec->spec;
2341 int idx = alc880_multi_pin_idx(nid);
2342 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
2343 AC_VERB_SET_CONNECT_SEL,
2344 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
2345 }
2346}
2347
2348static void alc880_auto_init_multi_out(struct hda_codec *codec)
2349{
2350 struct alc_spec *spec = codec->spec;
2351 int i;
2352
2353 for (i = 0; i < spec->autocfg.line_outs; i++) {
2354 hda_nid_t nid = spec->autocfg.line_out_pins[i];
2355 alc880_auto_set_output_and_unmute(codec, nid, PIN_OUT, i);
2356 }
2357}
2358
Takashi Iwai8d88bc32005-11-17 11:09:23 +01002359static void alc880_auto_init_extra_out(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002360{
2361 struct alc_spec *spec = codec->spec;
2362 hda_nid_t pin;
2363
Takashi Iwai8d88bc32005-11-17 11:09:23 +01002364 pin = spec->autocfg.speaker_pin;
2365 if (pin) /* connect to front */
2366 alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002367 pin = spec->autocfg.hp_pin;
2368 if (pin) /* connect to front */
2369 alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
2370}
2371
2372static void alc880_auto_init_analog_input(struct hda_codec *codec)
2373{
2374 struct alc_spec *spec = codec->spec;
2375 int i;
2376
2377 for (i = 0; i < AUTO_PIN_LAST; i++) {
2378 hda_nid_t nid = spec->autocfg.input_pins[i];
2379 if (alc880_is_input_pin(nid)) {
2380 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
2381 i <= AUTO_PIN_FRONT_MIC ? PIN_VREF80 : PIN_IN);
2382 if (nid != ALC880_PIN_CD_NID)
2383 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
2384 AMP_OUT_MUTE);
2385 }
2386 }
2387}
2388
2389/* parse the BIOS configuration and set up the alc_spec */
2390/* return 1 if successful, 0 if the proper config is not found, or a negative error code */
2391static int alc880_parse_auto_config(struct hda_codec *codec)
2392{
2393 struct alc_spec *spec = codec->spec;
2394 int err;
Kailang Yangdf694da2005-12-05 19:42:22 +01002395 static hda_nid_t alc880_ignore[] = { 0x1d, 0 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002396
Kailang Yangdf694da2005-12-05 19:42:22 +01002397 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
2398 alc880_ignore)) < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002399 return err;
Takashi Iwai8d88bc32005-11-17 11:09:23 +01002400 if (! spec->autocfg.line_outs && ! spec->autocfg.speaker_pin &&
2401 ! spec->autocfg.hp_pin)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002402 return 0; /* can't find valid BIOS pin config */
Kailang Yangdf694da2005-12-05 19:42:22 +01002403
2404 if ((err = alc880_auto_fill_dac_nids(spec, &spec->autocfg)) < 0 ||
2405 (err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 ||
Takashi Iwai8d88bc32005-11-17 11:09:23 +01002406 (err = alc880_auto_create_extra_out(spec, spec->autocfg.speaker_pin,
2407 "Speaker")) < 0 ||
2408 (err = alc880_auto_create_extra_out(spec, spec->autocfg.speaker_pin,
2409 "Headphone")) < 0 ||
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002410 (err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
2411 return err;
2412
2413 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
2414
2415 if (spec->autocfg.dig_out_pin)
2416 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
2417 if (spec->autocfg.dig_in_pin)
2418 spec->dig_in_nid = ALC880_DIGIN_NID;
2419
2420 if (spec->kctl_alloc)
2421 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2422
2423 spec->init_verbs[spec->num_init_verbs++] = alc880_volume_init_verbs;
2424
2425 spec->input_mux = &spec->private_imux;
2426
2427 return 1;
2428}
2429
2430/* init callback for auto-configuration model -- overriding the default init */
2431static int alc880_auto_init(struct hda_codec *codec)
2432{
2433 alc_init(codec);
2434 alc880_auto_init_multi_out(codec);
Takashi Iwai8d88bc32005-11-17 11:09:23 +01002435 alc880_auto_init_extra_out(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002436 alc880_auto_init_analog_input(codec);
2437 return 0;
2438}
2439
2440/*
2441 * OK, here we have finally the patch for ALC880
2442 */
2443
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444static int patch_alc880(struct hda_codec *codec)
2445{
2446 struct alc_spec *spec;
2447 int board_config;
Kailang Yangdf694da2005-12-05 19:42:22 +01002448 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449
Takashi Iwaie560d8d2005-09-09 14:21:46 +02002450 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451 if (spec == NULL)
2452 return -ENOMEM;
2453
2454 codec->spec = spec;
2455
2456 board_config = snd_hda_check_board_config(codec, alc880_cfg_tbl);
Takashi Iwai16ded522005-06-10 19:58:24 +02002457 if (board_config < 0 || board_config >= ALC880_MODEL_LAST) {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002458 printk(KERN_INFO "hda_codec: Unknown model for ALC880, trying auto-probe from BIOS...\n");
2459 board_config = ALC880_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460 }
2461
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002462 if (board_config == ALC880_AUTO) {
2463 /* automatic parse from the BIOS config */
2464 err = alc880_parse_auto_config(codec);
2465 if (err < 0) {
2466 alc_free(codec);
2467 return err;
2468 } else if (! err) {
2469 printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using 3-stack mode...\n");
2470 board_config = ALC880_3ST;
2471 }
2472 }
2473
Kailang Yangdf694da2005-12-05 19:42:22 +01002474 if (board_config != ALC880_AUTO)
2475 setup_preset(spec, &alc880_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476
2477 spec->stream_name_analog = "ALC880 Analog";
2478 spec->stream_analog_playback = &alc880_pcm_analog_playback;
2479 spec->stream_analog_capture = &alc880_pcm_analog_capture;
2480
2481 spec->stream_name_digital = "ALC880 Digital";
2482 spec->stream_digital_playback = &alc880_pcm_digital_playback;
2483 spec->stream_digital_capture = &alc880_pcm_digital_capture;
2484
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002485 if (! spec->adc_nids && spec->input_mux) {
2486 /* check whether NID 0x07 is valid */
Takashi Iwai54d17402005-11-21 16:33:22 +01002487 unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002488 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */
2489 if (wcap != AC_WID_AUD_IN) {
2490 spec->adc_nids = alc880_adc_nids_alt;
2491 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
2492 spec->mixers[spec->num_mixers] = alc880_capture_alt_mixer;
2493 spec->num_mixers++;
2494 } else {
2495 spec->adc_nids = alc880_adc_nids;
2496 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
2497 spec->mixers[spec->num_mixers] = alc880_capture_mixer;
2498 spec->num_mixers++;
2499 }
2500 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501
2502 codec->patch_ops = alc_patch_ops;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002503 if (board_config == ALC880_AUTO)
2504 codec->patch_ops.init = alc880_auto_init;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505
2506 return 0;
2507}
2508
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002509
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510/*
2511 * ALC260 support
2512 */
2513
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002514static hda_nid_t alc260_dac_nids[1] = {
2515 /* front */
2516 0x02,
2517};
2518
2519static hda_nid_t alc260_adc_nids[1] = {
2520 /* ADC0 */
2521 0x04,
2522};
2523
Kailang Yangdf694da2005-12-05 19:42:22 +01002524static hda_nid_t alc260_adc_nids_alt[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002525 /* ADC1 */
2526 0x05,
2527};
2528
Kailang Yangdf694da2005-12-05 19:42:22 +01002529static hda_nid_t alc260_hp_adc_nids[2] = {
2530 /* ADC1, 0 */
2531 0x05, 0x04
2532};
2533
Jonathan Woithed57fdac2006-02-28 11:38:35 +01002534/* NIDs used when simultaneous access to both ADCs makes sense. Note that
2535 * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
2536 */
2537static hda_nid_t alc260_dual_adc_nids[2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01002538 /* ADC0, ADC1 */
2539 0x04, 0x05
2540};
2541
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002542#define ALC260_DIGOUT_NID 0x03
2543#define ALC260_DIGIN_NID 0x06
2544
2545static struct hda_input_mux alc260_capture_source = {
2546 .num_items = 4,
2547 .items = {
2548 { "Mic", 0x0 },
2549 { "Front Mic", 0x1 },
2550 { "Line", 0x2 },
2551 { "CD", 0x4 },
2552 },
2553};
2554
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01002555/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
2556 * headphone jack and the internal CD lines.
Jonathan Woithea9430dd2005-09-16 19:12:48 +02002557 */
2558static struct hda_input_mux alc260_fujitsu_capture_source = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01002559 .num_items = 3,
Jonathan Woithea9430dd2005-09-16 19:12:48 +02002560 .items = {
2561 { "Mic/Line", 0x0 },
2562 { "CD", 0x4 },
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01002563 { "Headphone", 0x2 },
Jonathan Woithea9430dd2005-09-16 19:12:48 +02002564 },
2565};
2566
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01002567/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configutation to
2568 * the Fujitsu S702x, but jacks are marked differently. We won't allow
2569 * retasking the Headphone jack, so it won't be available here.
2570 */
2571static struct hda_input_mux alc260_acer_capture_source = {
2572 .num_items = 3,
2573 .items = {
2574 { "Mic", 0x0 },
2575 { "Line", 0x2 },
2576 { "CD", 0x4 },
2577 },
2578};
2579
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580/*
2581 * This is just place-holder, so there's something for alc_build_pcms to look
2582 * at when it calculates the maximum number of channels. ALC260 has no mixer
2583 * element which allows changing the channel mode, so the verb list is
2584 * never used.
2585 */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002586static struct hda_channel_mode alc260_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587 { 2, NULL },
2588};
2589
Kailang Yangdf694da2005-12-05 19:42:22 +01002590
2591/* Mixer combinations
2592 *
2593 * basic: base_output + input + pc_beep + capture
2594 * HP: base_output + input + capture_alt
2595 * HP_3013: hp_3013 + input + capture
2596 * fujitsu: fujitsu + capture
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01002597 * acer: acer + capture
Kailang Yangdf694da2005-12-05 19:42:22 +01002598 */
2599
2600static struct snd_kcontrol_new alc260_base_output_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02002601 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002602 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01002603 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
2604 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
2605 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
2606 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
2607 { } /* end */
2608};
2609
2610static struct snd_kcontrol_new alc260_input_mixer[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
2612 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
2613 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
2614 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
2615 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
2616 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
2617 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
2618 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619 { } /* end */
2620};
2621
Kailang Yangdf694da2005-12-05 19:42:22 +01002622static struct snd_kcontrol_new alc260_pc_beep_mixer[] = {
2623 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x07, 0x05, HDA_INPUT),
2624 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x07, 0x05, HDA_INPUT),
2625 { } /* end */
2626};
2627
2628static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
2629 HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
2630 HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
2631 HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
2632 HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
2633 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
2634 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
2635 HDA_CODEC_VOLUME_MONO("iSpeaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
2636 HDA_CODEC_MUTE_MONO("iSpeaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002637 { } /* end */
2638};
2639
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002640static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02002641 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002642 HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01002643 ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02002644 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
2645 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
2646 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
2647 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01002648 ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02002649 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
2650 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
2651 HDA_CODEC_VOLUME("Internal Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002652 HDA_BIND_MUTE("Internal Speaker Playback Switch", 0x09, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01002653 { } /* end */
2654};
2655
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01002656static struct snd_kcontrol_new alc260_acer_mixer[] = {
2657 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
2658 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
2659 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
2660 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
2661 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
2662 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
2663 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
2664 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
2665 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
2666 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
2667 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
2668 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
2669 { } /* end */
2670};
2671
Kailang Yangdf694da2005-12-05 19:42:22 +01002672/* capture mixer elements */
2673static struct snd_kcontrol_new alc260_capture_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02002674 HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT),
2675 HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01002676 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x05, 0x0, HDA_INPUT),
2677 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x05, 0x0, HDA_INPUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02002678 {
2679 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Kailang Yangdf694da2005-12-05 19:42:22 +01002680 /* The multiple "Capture Source" controls confuse alsamixer
2681 * So call somewhat different..
2682 * FIXME: the controls appear in the "playback" view!
2683 */
2684 /* .name = "Capture Source", */
2685 .name = "Input Source",
2686 .count = 2,
Jonathan Woithea9430dd2005-09-16 19:12:48 +02002687 .info = alc_mux_enum_info,
2688 .get = alc_mux_enum_get,
2689 .put = alc_mux_enum_put,
2690 },
2691 { } /* end */
2692};
2693
Kailang Yangdf694da2005-12-05 19:42:22 +01002694static struct snd_kcontrol_new alc260_capture_alt_mixer[] = {
2695 HDA_CODEC_VOLUME("Capture Volume", 0x05, 0x0, HDA_INPUT),
2696 HDA_CODEC_MUTE("Capture Switch", 0x05, 0x0, HDA_INPUT),
2697 {
2698 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2699 /* The multiple "Capture Source" controls confuse alsamixer
2700 * So call somewhat different..
2701 * FIXME: the controls appear in the "playback" view!
2702 */
2703 /* .name = "Capture Source", */
2704 .name = "Input Source",
2705 .count = 1,
2706 .info = alc_mux_enum_info,
2707 .get = alc_mux_enum_get,
2708 .put = alc_mux_enum_put,
2709 },
2710 { } /* end */
2711};
2712
2713/*
2714 * initialization verbs
2715 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716static struct hda_verb alc260_init_verbs[] = {
2717 /* Line In pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02002718 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02002720 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02002722 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 /* Mic2 (front panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02002724 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 /* LINE-2 is used for line-out in rear */
Takashi Iwai05acb862005-06-10 19:50:25 +02002726 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 /* select line-out */
Jonathan Woithefd56f2d2006-01-24 10:35:46 +01002728 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729 /* LINE-OUT pin */
Takashi Iwai05acb862005-06-10 19:50:25 +02002730 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731 /* enable HP */
Takashi Iwai05acb862005-06-10 19:50:25 +02002732 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 /* enable Mono */
Takashi Iwai05acb862005-06-10 19:50:25 +02002734 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2735 /* mute capture amp left and right */
Takashi Iwai16ded522005-06-10 19:58:24 +02002736 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 /* set connection select to line in (default select for this ADC) */
2738 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai16ded522005-06-10 19:58:24 +02002739 /* mute capture amp left and right */
2740 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2741 /* set connection select to line in (default select for this ADC) */
2742 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai05acb862005-06-10 19:50:25 +02002743 /* set vol=0 Line-Out mixer amp left and right */
2744 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2745 /* unmute pin widget amp left and right (no gain on this amp) */
2746 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2747 /* set vol=0 HP mixer amp left and right */
2748 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2749 /* unmute pin widget amp left and right (no gain on this amp) */
2750 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2751 /* set vol=0 Mono mixer amp left and right */
2752 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2753 /* unmute pin widget amp left and right (no gain on this amp) */
2754 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2755 /* unmute LINE-2 out pin */
2756 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */
Takashi Iwai05acb862005-06-10 19:50:25 +02002758 /* mute CD */
Takashi Iwai16ded522005-06-10 19:58:24 +02002759 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Takashi Iwai05acb862005-06-10 19:50:25 +02002760 /* mute Line In */
Takashi Iwai16ded522005-06-10 19:58:24 +02002761 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwai05acb862005-06-10 19:50:25 +02002762 /* mute Mic */
Takashi Iwai16ded522005-06-10 19:58:24 +02002763 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
Takashi Iwai05acb862005-06-10 19:50:25 +02002765 /* mute Front out path */
2766 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2767 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2768 /* mute Headphone out path */
2769 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2770 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2771 /* mute Mono out path */
2772 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2773 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 { }
2775};
2776
Kailang Yangdf694da2005-12-05 19:42:22 +01002777static struct hda_verb alc260_hp_init_verbs[] = {
2778 /* Headphone and output */
2779 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
2780 /* mono output */
2781 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2782 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2783 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
2784 /* Mic2 (front panel) pin widget for input and vref at 80% */
2785 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
2786 /* Line In pin widget for input */
2787 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
2788 /* Line-2 pin widget for output */
2789 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2790 /* CD pin widget for input */
2791 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
2792 /* unmute amp left and right */
2793 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
2794 /* set connection select to line in (default select for this ADC) */
2795 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
2796 /* unmute Line-Out mixer amp left and right (volume = 0) */
2797 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
2798 /* mute pin widget amp left and right (no gain on this amp) */
2799 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
2800 /* unmute HP mixer amp left and right (volume = 0) */
2801 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
2802 /* mute pin widget amp left and right (no gain on this amp) */
2803 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
2804 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */
2805 /* unmute CD */
2806 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
2807 /* unmute Line In */
2808 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
2809 /* unmute Mic */
2810 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2811 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
2812 /* Unmute Front out path */
2813 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2814 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2815 /* Unmute Headphone out path */
2816 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2817 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2818 /* Unmute Mono out path */
2819 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2820 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2821 { }
2822};
2823
2824static struct hda_verb alc260_hp_3013_init_verbs[] = {
2825 /* Line out and output */
2826 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2827 /* mono output */
2828 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2829 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2830 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
2831 /* Mic2 (front panel) pin widget for input and vref at 80% */
2832 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
2833 /* Line In pin widget for input */
2834 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
2835 /* Headphone pin widget for output */
2836 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
2837 /* CD pin widget for input */
2838 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
2839 /* unmute amp left and right */
2840 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
2841 /* set connection select to line in (default select for this ADC) */
2842 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
2843 /* unmute Line-Out mixer amp left and right (volume = 0) */
2844 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
2845 /* mute pin widget amp left and right (no gain on this amp) */
2846 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
2847 /* unmute HP mixer amp left and right (volume = 0) */
2848 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
2849 /* mute pin widget amp left and right (no gain on this amp) */
2850 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
2851 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */
2852 /* unmute CD */
2853 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
2854 /* unmute Line In */
2855 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
2856 /* unmute Mic */
2857 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2858 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
2859 /* Unmute Front out path */
2860 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2861 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2862 /* Unmute Headphone out path */
2863 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2864 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2865 /* Unmute Mono out path */
2866 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2867 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2868 { }
2869};
2870
Jonathan Woithea9430dd2005-09-16 19:12:48 +02002871/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
2872 * laptops.
2873 */
2874static struct hda_verb alc260_fujitsu_init_verbs[] = {
2875 /* Disable all GPIOs */
2876 {0x01, AC_VERB_SET_GPIO_MASK, 0},
2877 /* Internal speaker is connected to headphone pin */
2878 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2879 /* Headphone/Line-out jack connects to Line1 pin; make it an output */
2880 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Jonathan Woithef7ace402006-02-28 11:46:14 +01002881 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
2882 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2883 /* Ensure all other unused pins are disabled and muted. */
2884 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2885 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02002886 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01002887 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02002888 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01002889 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2890 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2891 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02002892
Jonathan Woithef7ace402006-02-28 11:46:14 +01002893 /* Disable digital (SPDIF) pins */
2894 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
2895 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01002896
Jonathan Woithef7ace402006-02-28 11:46:14 +01002897 /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
2898 * when acting as an output.
2899 */
2900 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
2901
2902 /* Start with output sum widgets muted and their output gains at min */
Takashi Iwai8b33a5a2006-02-09 11:57:01 +01002903 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2904 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2905 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2906 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2907 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2908 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2909 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2910 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2911 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02002912
Jonathan Woithef7ace402006-02-28 11:46:14 +01002913 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
2914 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2915 /* Unmute Line1 pin widget output buffer since it starts as an output.
2916 * If the pin mode is changed by the user the pin mode control will
2917 * take care of enabling the pin's input/output buffers as needed.
2918 * Therefore there's no need to enable the input buffer at this
2919 * stage.
Jonathan Woithecdcd9262006-02-28 11:36:42 +01002920 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01002921 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithecdcd9262006-02-28 11:36:42 +01002922 /* Unmute input buffer of pin widget used for Line-in (no equiv
2923 * mixer ctrl)
2924 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01002925 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02002926
Jonathan Woithef7ace402006-02-28 11:46:14 +01002927 /* Mute capture amp left and right */
2928 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2929 /* Set ADC connection select to match default mixer setting - line
2930 * in (on mic1 pin)
2931 */
2932 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02002933
Jonathan Woithef7ace402006-02-28 11:46:14 +01002934 /* Do the same for the second ADC: mute capture input amp and
2935 * set ADC connection to line in (on mic1 pin)
2936 */
2937 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2938 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01002939
Jonathan Woithef7ace402006-02-28 11:46:14 +01002940 /* Mute all inputs to mixer widget (even unconnected ones) */
2941 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
2942 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
2943 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
2944 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
2945 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
2946 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
2947 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
2948 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
Takashi Iwai4a471b72005-12-07 13:56:29 +01002949
2950 { }
Jonathan Woithea9430dd2005-09-16 19:12:48 +02002951};
2952
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01002953/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
2954 * similar laptops (adapted from Fujitsu init verbs).
2955 */
2956static struct hda_verb alc260_acer_init_verbs[] = {
2957 /* On TravelMate laptops, GPIO 0 enables the internal speaker and
2958 * the headphone jack. Turn this on and rely on the standard mute
2959 * methods whenever the user wants to turn these outputs off.
2960 */
2961 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
2962 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
2963 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
2964 /* Internal speaker/Headphone jack is connected to Line-out pin */
2965 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2966 /* Internal microphone/Mic jack is connected to Mic1 pin */
2967 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
2968 /* Line In jack is connected to Line1 pin */
2969 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2970 /* Ensure all other unused pins are disabled and muted. */
2971 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2972 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2973 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2974 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2975 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2976 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2977 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2978 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2979 /* Disable digital (SPDIF) pins */
2980 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
2981 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
2982
2983 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
2984 * bus when acting as outputs.
2985 */
2986 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
2987 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
2988
2989 /* Start with output sum widgets muted and their output gains at min */
2990 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2991 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2992 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2993 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2994 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2995 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2996 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2997 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2998 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2999
3000 /* Unmute Line-out pin widget amp left and right (no equiv mixer ctrl) */
3001 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3002 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
3003 * inputs. If the pin mode is changed by the user the pin mode control
3004 * will take care of enabling the pin's input/output buffers as needed.
3005 * Therefore there's no need to enable the input buffer at this
3006 * stage.
3007 */
3008 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3009 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3010
3011 /* Mute capture amp left and right */
3012 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3013 /* Set ADC connection select to match default mixer setting - mic
3014 * (on mic1 pin)
3015 */
3016 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
3017
3018 /* Do similar with the second ADC: mute capture input amp and
3019 * set ADC connection to line (on line1 pin)
3020 */
3021 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3022 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
3023
3024 /* Mute all inputs to mixer widget (even unconnected ones) */
3025 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
3026 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
3027 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
3028 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
3029 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
3030 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
3031 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
3032 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
3033
3034 { }
3035};
3036
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01003037/* Test configuration for debugging, modelled after the ALC880 test
3038 * configuration.
3039 */
3040#ifdef CONFIG_SND_DEBUG
3041static hda_nid_t alc260_test_dac_nids[1] = {
3042 0x02,
3043};
3044static hda_nid_t alc260_test_adc_nids[2] = {
3045 0x04, 0x05,
3046};
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01003047/* This is a bit messy since the two input muxes in the ALC260 have slight
3048 * variations in their signal assignments. The ideal way to deal with this
3049 * is to extend alc_spec.input_mux to allow a different input MUX for each
3050 * ADC. For the purposes of the test model it's sufficient to just list
3051 * both options for affected signal indices. The separate input mux
3052 * functionality only needs to be considered if a model comes along which
3053 * actually uses signals 0x5, 0x6 and 0x7 for something which makes sense to
3054 * record.
3055 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01003056static struct hda_input_mux alc260_test_capture_source = {
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01003057 .num_items = 8,
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01003058 .items = {
3059 { "MIC1 pin", 0x0 },
3060 { "MIC2 pin", 0x1 },
3061 { "LINE1 pin", 0x2 },
3062 { "LINE2 pin", 0x3 },
3063 { "CD pin", 0x4 },
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01003064 { "LINE-OUT pin (cap1), Mixer (cap2)", 0x5 },
3065 { "HP-OUT pin (cap1), LINE-OUT pin (cap2)", 0x6 },
3066 { "HP-OUT pin (cap2 only)", 0x7 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01003067 },
3068};
3069static struct snd_kcontrol_new alc260_test_mixer[] = {
3070 /* Output driver widgets */
3071 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
3072 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
3073 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
3074 HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
3075 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
3076 HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
3077
3078 /* Modes for retasking pin widgets */
3079 ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
3080 ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
3081 ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
3082 ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
3083 ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
3084 ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
3085
3086 /* Loopback mixer controls */
3087 HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
3088 HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
3089 HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
3090 HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
3091 HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
3092 HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
3093 HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
3094 HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
3095 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
3096 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
3097 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
3098 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
3099 HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
3100 HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
3101 HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
3102 HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01003103
3104 /* Controls for GPIO pins, assuming they are configured as outputs */
3105 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
3106 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
3107 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
3108 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
3109
Jonathan Woithe92621f12006-02-28 11:47:47 +01003110 /* Switches to allow the digital IO pins to be enabled. The datasheet
3111 * is ambigious as to which NID is which; testing on laptops which
3112 * make this output available should provide clarification.
3113 */
3114 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
3115 ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
3116
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01003117 { } /* end */
3118};
3119static struct hda_verb alc260_test_init_verbs[] = {
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01003120 /* Enable all GPIOs as outputs with an initial value of 0 */
3121 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
3122 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
3123 {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
3124
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01003125 /* Enable retasking pins as output, initially without power amp */
3126 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3127 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3128 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3129 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3130 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3131 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3132
Jonathan Woithe92621f12006-02-28 11:47:47 +01003133 /* Disable digital (SPDIF) pins initially, but users can enable
3134 * them via a mixer switch. In the case of SPDIF-out, this initverb
3135 * payload also sets the generation to 0, output to be in "consumer"
3136 * PCM format, copyright asserted, no pre-emphasis and no validity
3137 * control.
3138 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01003139 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
3140 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
3141
Jonathan Woithef7ace402006-02-28 11:46:14 +01003142 /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01003143 * OUT1 sum bus when acting as an output.
3144 */
3145 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
3146 {0x0c, AC_VERB_SET_CONNECT_SEL, 0},
3147 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
3148 {0x0e, AC_VERB_SET_CONNECT_SEL, 0},
3149
3150 /* Start with output sum widgets muted and their output gains at min */
3151 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3152 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3153 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3154 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3155 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3156 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3157 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3158 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3159 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3160
Jonathan Woithecdcd9262006-02-28 11:36:42 +01003161 /* Unmute retasking pin widget output buffers since the default
3162 * state appears to be output. As the pin mode is changed by the
3163 * user the pin mode control will take care of enabling the pin's
3164 * input/output buffers as needed.
3165 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01003166 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3167 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3168 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3169 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3170 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3171 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3172 /* Also unmute the mono-out pin widget */
3173 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3174
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01003175 /* Mute capture amp left and right */
3176 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithef7ace402006-02-28 11:46:14 +01003177 /* Set ADC connection select to match default mixer setting (mic1
3178 * pin)
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01003179 */
3180 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
3181
3182 /* Do the same for the second ADC: mute capture input amp and
Jonathan Woithef7ace402006-02-28 11:46:14 +01003183 * set ADC connection to mic1 pin
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01003184 */
3185 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3186 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
3187
3188 /* Mute all inputs to mixer widget (even unconnected ones) */
3189 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
3190 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
3191 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
3192 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
3193 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
3194 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
3195 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
3196 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
3197
3198 { }
3199};
3200#endif
3201
Linus Torvalds1da177e2005-04-16 15:20:36 -07003202static struct hda_pcm_stream alc260_pcm_analog_playback = {
3203 .substreams = 1,
3204 .channels_min = 2,
3205 .channels_max = 2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003206};
3207
3208static struct hda_pcm_stream alc260_pcm_analog_capture = {
3209 .substreams = 1,
3210 .channels_min = 2,
3211 .channels_max = 2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003212};
3213
Takashi Iwaia3bcba32005-12-06 19:05:29 +01003214#define alc260_pcm_digital_playback alc880_pcm_digital_playback
3215#define alc260_pcm_digital_capture alc880_pcm_digital_capture
3216
Kailang Yangdf694da2005-12-05 19:42:22 +01003217/*
3218 * for BIOS auto-configuration
3219 */
3220
3221static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
3222 const char *pfx)
3223{
3224 hda_nid_t nid_vol;
3225 unsigned long vol_val, sw_val;
3226 char name[32];
3227 int err;
3228
3229 if (nid >= 0x0f && nid < 0x11) {
3230 nid_vol = nid - 0x7;
3231 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
3232 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
3233 } else if (nid == 0x11) {
3234 nid_vol = nid - 0x7;
3235 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT);
3236 sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
3237 } else if (nid >= 0x12 && nid <= 0x15) {
3238 nid_vol = 0x08;
3239 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
3240 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
3241 } else
3242 return 0; /* N/A */
3243
3244 snprintf(name, sizeof(name), "%s Playback Volume", pfx);
3245 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, name, vol_val)) < 0)
3246 return err;
3247 snprintf(name, sizeof(name), "%s Playback Switch", pfx);
3248 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, sw_val)) < 0)
3249 return err;
3250 return 1;
3251}
3252
3253/* add playback controls from the parsed DAC table */
3254static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
3255 const struct auto_pin_cfg *cfg)
3256{
3257 hda_nid_t nid;
3258 int err;
3259
3260 spec->multiout.num_dacs = 1;
3261 spec->multiout.dac_nids = spec->private_dac_nids;
3262 spec->multiout.dac_nids[0] = 0x02;
3263
3264 nid = cfg->line_out_pins[0];
3265 if (nid) {
3266 err = alc260_add_playback_controls(spec, nid, "Front");
3267 if (err < 0)
3268 return err;
3269 }
3270
3271 nid = cfg->speaker_pin;
3272 if (nid) {
3273 err = alc260_add_playback_controls(spec, nid, "Speaker");
3274 if (err < 0)
3275 return err;
3276 }
3277
3278 nid = cfg->hp_pin;
3279 if (nid) {
3280 err = alc260_add_playback_controls(spec, nid, "Headphone");
3281 if (err < 0)
3282 return err;
3283 }
3284 return 0;
3285}
3286
3287/* create playback/capture controls for input pins */
3288static int alc260_auto_create_analog_input_ctls(struct alc_spec *spec,
3289 const struct auto_pin_cfg *cfg)
3290{
Kailang Yangdf694da2005-12-05 19:42:22 +01003291 struct hda_input_mux *imux = &spec->private_imux;
3292 int i, err, idx;
3293
3294 for (i = 0; i < AUTO_PIN_LAST; i++) {
3295 if (cfg->input_pins[i] >= 0x12) {
3296 idx = cfg->input_pins[i] - 0x12;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003297 err = new_analog_input(spec, cfg->input_pins[i],
3298 auto_pin_cfg_labels[i], idx, 0x07);
Kailang Yangdf694da2005-12-05 19:42:22 +01003299 if (err < 0)
3300 return err;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003301 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +01003302 imux->items[imux->num_items].index = idx;
3303 imux->num_items++;
3304 }
3305 if ((cfg->input_pins[i] >= 0x0f) && (cfg->input_pins[i] <= 0x10)){
3306 idx = cfg->input_pins[i] - 0x09;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003307 err = new_analog_input(spec, cfg->input_pins[i],
3308 auto_pin_cfg_labels[i], idx, 0x07);
Kailang Yangdf694da2005-12-05 19:42:22 +01003309 if (err < 0)
3310 return err;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003311 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +01003312 imux->items[imux->num_items].index = idx;
3313 imux->num_items++;
3314 }
3315 }
3316 return 0;
3317}
3318
3319static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
3320 hda_nid_t nid, int pin_type,
3321 int sel_idx)
3322{
3323 /* set as output */
3324 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
3325 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
3326 /* need the manual connection? */
3327 if (nid >= 0x12) {
3328 int idx = nid - 0x12;
3329 snd_hda_codec_write(codec, idx + 0x0b, 0,
3330 AC_VERB_SET_CONNECT_SEL, sel_idx);
3331
3332 }
3333}
3334
3335static void alc260_auto_init_multi_out(struct hda_codec *codec)
3336{
3337 struct alc_spec *spec = codec->spec;
3338 hda_nid_t nid;
3339
3340 nid = spec->autocfg.line_out_pins[0];
3341 if (nid)
3342 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
3343
3344 nid = spec->autocfg.speaker_pin;
3345 if (nid)
3346 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
3347
3348 nid = spec->autocfg.hp_pin;
3349 if (nid)
3350 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
3351}
3352
3353#define ALC260_PIN_CD_NID 0x16
3354static void alc260_auto_init_analog_input(struct hda_codec *codec)
3355{
3356 struct alc_spec *spec = codec->spec;
3357 int i;
3358
3359 for (i = 0; i < AUTO_PIN_LAST; i++) {
3360 hda_nid_t nid = spec->autocfg.input_pins[i];
3361 if (nid >= 0x12) {
3362 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
3363 i <= AUTO_PIN_FRONT_MIC ? PIN_VREF80 : PIN_IN);
3364 if (nid != ALC260_PIN_CD_NID)
3365 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
3366 AMP_OUT_MUTE);
3367 }
3368 }
3369}
3370
3371/*
3372 * generic initialization of ADC, input mixers and output mixers
3373 */
3374static struct hda_verb alc260_volume_init_verbs[] = {
3375 /*
3376 * Unmute ADC0-1 and set the default input to mic-in
3377 */
3378 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
3379 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3380 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
3381 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3382
3383 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
3384 * mixer widget
3385 * Note: PASD motherboards uses the Line In 2 as the input for front panel
3386 * mic (mic 2)
3387 */
3388 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
3389 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3390 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3391 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
3392 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
3393 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
3394
3395 /*
3396 * Set up output mixers (0x08 - 0x0a)
3397 */
3398 /* set vol=0 to output mixers */
3399 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3400 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3401 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3402 /* set up input amps for analog loopback */
3403 /* Amp Indices: DAC = 0, mixer = 1 */
3404 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3405 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3406 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3407 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3408 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3409 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3410
3411 { }
3412};
3413
3414static int alc260_parse_auto_config(struct hda_codec *codec)
3415{
3416 struct alc_spec *spec = codec->spec;
3417 unsigned int wcap;
3418 int err;
3419 static hda_nid_t alc260_ignore[] = { 0x17, 0 };
3420
3421 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
3422 alc260_ignore)) < 0)
3423 return err;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003424 if ((err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0)
3425 return err;
3426 if (! spec->kctl_alloc)
Kailang Yangdf694da2005-12-05 19:42:22 +01003427 return 0; /* can't find valid BIOS pin config */
Takashi Iwai4a471b72005-12-07 13:56:29 +01003428 if ((err = alc260_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01003429 return err;
3430
3431 spec->multiout.max_channels = 2;
3432
3433 if (spec->autocfg.dig_out_pin)
3434 spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
3435 if (spec->kctl_alloc)
3436 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
3437
3438 spec->init_verbs[spec->num_init_verbs++] = alc260_volume_init_verbs;
3439
3440 spec->input_mux = &spec->private_imux;
3441
3442 /* check whether NID 0x04 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +01003443 wcap = get_wcaps(codec, 0x04);
Kailang Yangdf694da2005-12-05 19:42:22 +01003444 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */
3445 if (wcap != AC_WID_AUD_IN) {
3446 spec->adc_nids = alc260_adc_nids_alt;
3447 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
3448 spec->mixers[spec->num_mixers] = alc260_capture_alt_mixer;
Kailang Yangdf694da2005-12-05 19:42:22 +01003449 } else {
3450 spec->adc_nids = alc260_adc_nids;
3451 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
3452 spec->mixers[spec->num_mixers] = alc260_capture_mixer;
Kailang Yangdf694da2005-12-05 19:42:22 +01003453 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01003454 spec->num_mixers++;
Kailang Yangdf694da2005-12-05 19:42:22 +01003455
3456 return 1;
3457}
3458
3459/* init callback for auto-configuration model -- overriding the default init */
3460static int alc260_auto_init(struct hda_codec *codec)
3461{
3462 alc_init(codec);
3463 alc260_auto_init_multi_out(codec);
3464 alc260_auto_init_analog_input(codec);
3465 return 0;
3466}
3467
3468/*
3469 * ALC260 configurations
3470 */
Takashi Iwai16ded522005-06-10 19:58:24 +02003471static struct hda_board_config alc260_cfg_tbl[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01003472 { .modelname = "basic", .config = ALC260_BASIC },
Takashi Iwaib14e77e2006-01-11 18:10:50 +01003473 { .pci_subvendor = 0x104d, .pci_subdevice = 0x81bb,
3474 .config = ALC260_BASIC }, /* Sony VAIO */
Takashi Iwai16ded522005-06-10 19:58:24 +02003475 { .modelname = "hp", .config = ALC260_HP },
Kailang Yangdf694da2005-12-05 19:42:22 +01003476 { .pci_subvendor = 0x103c, .pci_subdevice = 0x3010, .config = ALC260_HP },
3477 { .pci_subvendor = 0x103c, .pci_subdevice = 0x3011, .config = ALC260_HP },
3478 { .pci_subvendor = 0x103c, .pci_subdevice = 0x3012, .config = ALC260_HP },
3479 { .pci_subvendor = 0x103c, .pci_subdevice = 0x3013, .config = ALC260_HP_3013 },
3480 { .pci_subvendor = 0x103c, .pci_subdevice = 0x3014, .config = ALC260_HP },
3481 { .pci_subvendor = 0x103c, .pci_subdevice = 0x3015, .config = ALC260_HP },
3482 { .pci_subvendor = 0x103c, .pci_subdevice = 0x3016, .config = ALC260_HP },
3483 { .modelname = "fujitsu", .config = ALC260_FUJITSU_S702X },
3484 { .pci_subvendor = 0x10cf, .pci_subdevice = 0x1326, .config = ALC260_FUJITSU_S702X },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01003485 { .modelname = "acer", .config = ALC260_ACER },
3486 { .pci_subvendor = 0x1025, .pci_subdevice = 0x008f, .config = ALC260_ACER },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01003487#ifdef CONFIG_SND_DEBUG
3488 { .modelname = "test", .config = ALC260_TEST },
3489#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01003490 { .modelname = "auto", .config = ALC260_AUTO },
Takashi Iwai16ded522005-06-10 19:58:24 +02003491 {}
3492};
3493
Kailang Yangdf694da2005-12-05 19:42:22 +01003494static struct alc_config_preset alc260_presets[] = {
3495 [ALC260_BASIC] = {
3496 .mixers = { alc260_base_output_mixer,
3497 alc260_input_mixer,
3498 alc260_pc_beep_mixer,
3499 alc260_capture_mixer },
3500 .init_verbs = { alc260_init_verbs },
3501 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
3502 .dac_nids = alc260_dac_nids,
3503 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
3504 .adc_nids = alc260_adc_nids,
3505 .num_channel_mode = ARRAY_SIZE(alc260_modes),
3506 .channel_mode = alc260_modes,
3507 .input_mux = &alc260_capture_source,
3508 },
3509 [ALC260_HP] = {
3510 .mixers = { alc260_base_output_mixer,
3511 alc260_input_mixer,
3512 alc260_capture_alt_mixer },
3513 .init_verbs = { alc260_hp_init_verbs },
3514 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
3515 .dac_nids = alc260_dac_nids,
3516 .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
3517 .adc_nids = alc260_hp_adc_nids,
3518 .num_channel_mode = ARRAY_SIZE(alc260_modes),
3519 .channel_mode = alc260_modes,
3520 .input_mux = &alc260_capture_source,
3521 },
3522 [ALC260_HP_3013] = {
3523 .mixers = { alc260_hp_3013_mixer,
3524 alc260_input_mixer,
3525 alc260_capture_alt_mixer },
3526 .init_verbs = { alc260_hp_3013_init_verbs },
3527 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
3528 .dac_nids = alc260_dac_nids,
3529 .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
3530 .adc_nids = alc260_hp_adc_nids,
3531 .num_channel_mode = ARRAY_SIZE(alc260_modes),
3532 .channel_mode = alc260_modes,
3533 .input_mux = &alc260_capture_source,
3534 },
3535 [ALC260_FUJITSU_S702X] = {
3536 .mixers = { alc260_fujitsu_mixer,
3537 alc260_capture_mixer },
3538 .init_verbs = { alc260_fujitsu_init_verbs },
3539 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
3540 .dac_nids = alc260_dac_nids,
Jonathan Woithed57fdac2006-02-28 11:38:35 +01003541 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
3542 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01003543 .num_channel_mode = ARRAY_SIZE(alc260_modes),
3544 .channel_mode = alc260_modes,
3545 .input_mux = &alc260_fujitsu_capture_source,
3546 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01003547 [ALC260_ACER] = {
3548 .mixers = { alc260_acer_mixer,
3549 alc260_capture_mixer },
3550 .init_verbs = { alc260_acer_init_verbs },
3551 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
3552 .dac_nids = alc260_dac_nids,
3553 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
3554 .adc_nids = alc260_dual_adc_nids,
3555 .num_channel_mode = ARRAY_SIZE(alc260_modes),
3556 .channel_mode = alc260_modes,
3557 .input_mux = &alc260_acer_capture_source,
3558 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01003559#ifdef CONFIG_SND_DEBUG
3560 [ALC260_TEST] = {
3561 .mixers = { alc260_test_mixer,
3562 alc260_capture_mixer },
3563 .init_verbs = { alc260_test_init_verbs },
3564 .num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
3565 .dac_nids = alc260_test_dac_nids,
3566 .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
3567 .adc_nids = alc260_test_adc_nids,
3568 .num_channel_mode = ARRAY_SIZE(alc260_modes),
3569 .channel_mode = alc260_modes,
3570 .input_mux = &alc260_test_capture_source,
3571 },
3572#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01003573};
3574
Linus Torvalds1da177e2005-04-16 15:20:36 -07003575static int patch_alc260(struct hda_codec *codec)
3576{
3577 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01003578 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003580 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003581 if (spec == NULL)
3582 return -ENOMEM;
3583
3584 codec->spec = spec;
3585
Takashi Iwai16ded522005-06-10 19:58:24 +02003586 board_config = snd_hda_check_board_config(codec, alc260_cfg_tbl);
3587 if (board_config < 0 || board_config >= ALC260_MODEL_LAST) {
3588 snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01003589 board_config = ALC260_AUTO;
Takashi Iwai16ded522005-06-10 19:58:24 +02003590 }
3591
Kailang Yangdf694da2005-12-05 19:42:22 +01003592 if (board_config == ALC260_AUTO) {
3593 /* automatic parse from the BIOS config */
3594 err = alc260_parse_auto_config(codec);
3595 if (err < 0) {
3596 alc_free(codec);
3597 return err;
3598 } else if (! err) {
3599 printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using base mode...\n");
3600 board_config = ALC260_BASIC;
3601 }
Takashi Iwai16ded522005-06-10 19:58:24 +02003602 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603
Kailang Yangdf694da2005-12-05 19:42:22 +01003604 if (board_config != ALC260_AUTO)
3605 setup_preset(spec, &alc260_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606
3607 spec->stream_name_analog = "ALC260 Analog";
3608 spec->stream_analog_playback = &alc260_pcm_analog_playback;
3609 spec->stream_analog_capture = &alc260_pcm_analog_capture;
3610
Takashi Iwaia3bcba32005-12-06 19:05:29 +01003611 spec->stream_name_digital = "ALC260 Digital";
3612 spec->stream_digital_playback = &alc260_pcm_digital_playback;
3613 spec->stream_digital_capture = &alc260_pcm_digital_capture;
3614
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01003616 if (board_config == ALC260_AUTO)
3617 codec->patch_ops.init = alc260_auto_init;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003618
3619 return 0;
3620}
3621
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003622
Linus Torvalds1da177e2005-04-16 15:20:36 -07003623/*
3624 * ALC882 support
3625 *
3626 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
3627 * configuration. Each pin widget can choose any input DACs and a mixer.
3628 * Each ADC is connected from a mixer of all inputs. This makes possible
3629 * 6-channel independent captures.
3630 *
3631 * In addition, an independent DAC for the multi-playback (not used in this
3632 * driver yet).
3633 */
Kailang Yangdf694da2005-12-05 19:42:22 +01003634#define ALC882_DIGOUT_NID 0x06
3635#define ALC882_DIGIN_NID 0x0a
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01003637static struct hda_channel_mode alc882_ch_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638 { 8, NULL }
3639};
3640
3641static hda_nid_t alc882_dac_nids[4] = {
3642 /* front, rear, clfe, rear_surr */
3643 0x02, 0x03, 0x04, 0x05
3644};
3645
Kailang Yangdf694da2005-12-05 19:42:22 +01003646/* identical with ALC880 */
3647#define alc882_adc_nids alc880_adc_nids
3648#define alc882_adc_nids_alt alc880_adc_nids_alt
Linus Torvalds1da177e2005-04-16 15:20:36 -07003649
3650/* input MUX */
3651/* FIXME: should be a matrix-type input source selection */
3652
3653static struct hda_input_mux alc882_capture_source = {
3654 .num_items = 4,
3655 .items = {
3656 { "Mic", 0x0 },
3657 { "Front Mic", 0x1 },
3658 { "Line", 0x2 },
3659 { "CD", 0x4 },
3660 },
3661};
3662
3663#define alc882_mux_enum_info alc_mux_enum_info
3664#define alc882_mux_enum_get alc_mux_enum_get
3665
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003666static int alc882_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003667{
3668 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3669 struct alc_spec *spec = codec->spec;
3670 const struct hda_input_mux *imux = spec->input_mux;
3671 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
3672 static hda_nid_t capture_mixers[3] = { 0x24, 0x23, 0x22 };
3673 hda_nid_t nid = capture_mixers[adc_idx];
3674 unsigned int *cur_val = &spec->cur_mux[adc_idx];
3675 unsigned int i, idx;
3676
3677 idx = ucontrol->value.enumerated.item[0];
3678 if (idx >= imux->num_items)
3679 idx = imux->num_items - 1;
3680 if (*cur_val == idx && ! codec->in_resume)
3681 return 0;
3682 for (i = 0; i < imux->num_items; i++) {
3683 unsigned int v = (i == idx) ? 0x7000 : 0x7080;
3684 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
3685 v | (imux->items[i].index << 8));
3686 }
3687 *cur_val = idx;
3688 return 1;
3689}
3690
Kailang Yangdf694da2005-12-05 19:42:22 +01003691/*
3692 * 6ch mode
3693 */
3694static struct hda_verb alc882_sixstack_ch6_init[] = {
3695 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
3696 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
3697 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
3698 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
3699 { } /* end */
3700};
3701
3702/*
3703 * 8ch mode
3704 */
3705static struct hda_verb alc882_sixstack_ch8_init[] = {
3706 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
3707 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
3708 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
3709 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
3710 { } /* end */
3711};
3712
3713static struct hda_channel_mode alc882_sixstack_modes[2] = {
3714 { 6, alc882_sixstack_ch6_init },
3715 { 8, alc882_sixstack_ch8_init },
3716};
3717
Linus Torvalds1da177e2005-04-16 15:20:36 -07003718/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
3719 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
3720 */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003721static struct snd_kcontrol_new alc882_base_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02003722 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003723 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02003724 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003725 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02003726 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
3727 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003728 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
3729 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02003730 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003731 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003732 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
3733 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
3734 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
3735 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
3736 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
3737 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3738 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
3739 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3740 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
3741 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
3742 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
3743 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
3744 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
3745 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
3746 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
3747 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
3748 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
3749 {
3750 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3751 /* .name = "Capture Source", */
3752 .name = "Input Source",
3753 .count = 3,
3754 .info = alc882_mux_enum_info,
3755 .get = alc882_mux_enum_get,
3756 .put = alc882_mux_enum_put,
3757 },
3758 { } /* end */
3759};
3760
Kailang Yangdf694da2005-12-05 19:42:22 +01003761static struct snd_kcontrol_new alc882_chmode_mixer[] = {
3762 {
3763 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3764 .name = "Channel Mode",
3765 .info = alc_ch_mode_info,
3766 .get = alc_ch_mode_get,
3767 .put = alc_ch_mode_put,
3768 },
3769 { } /* end */
3770};
3771
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772static struct hda_verb alc882_init_verbs[] = {
3773 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Takashi Iwai05acb862005-06-10 19:50:25 +02003774 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3775 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3776 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777 /* Rear mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02003778 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3779 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3780 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003781 /* CLFE mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02003782 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3783 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3784 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003785 /* Side mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02003786 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3787 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3788 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003790 /* Front Pin: output 0 (0x0c) */
Takashi Iwai05acb862005-06-10 19:50:25 +02003791 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02003792 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003793 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003794 /* Rear Pin: output 1 (0x0d) */
Takashi Iwai05acb862005-06-10 19:50:25 +02003795 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02003796 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003797 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003798 /* CLFE Pin: output 2 (0x0e) */
Takashi Iwai05acb862005-06-10 19:50:25 +02003799 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02003800 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003801 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003802 /* Side Pin: output 3 (0x0f) */
Takashi Iwai05acb862005-06-10 19:50:25 +02003803 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02003804 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003805 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003806 /* Mic (rear) pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02003807 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003808 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3809 /* Front Mic pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02003810 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003811 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3812 /* Line In pin: input */
Takashi Iwai05acb862005-06-10 19:50:25 +02003813 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003814 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3815 /* Line-2 In: Headphone output (output 0 - 0x0c) */
3816 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3817 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3818 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003819 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02003820 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003821
3822 /* FIXME: use matrix-type input source selection */
3823 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
3824 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Takashi Iwai05acb862005-06-10 19:50:25 +02003825 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3826 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3827 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3828 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003829 /* Input mixer2 */
Takashi Iwai05acb862005-06-10 19:50:25 +02003830 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3831 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3832 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3833 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003834 /* Input mixer3 */
Takashi Iwai05acb862005-06-10 19:50:25 +02003835 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3836 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3837 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3838 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
3839 /* ADC1: mute amp left and right */
3840 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003841 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02003842 /* ADC2: mute amp left and right */
3843 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003844 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02003845 /* ADC3: mute amp left and right */
3846 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003847 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003848
3849 { }
3850};
3851
Kailang Yangdf694da2005-12-05 19:42:22 +01003852/*
3853 * generic initialization of ADC, input mixers and output mixers
3854 */
3855static struct hda_verb alc882_auto_init_verbs[] = {
3856 /*
3857 * Unmute ADC0-2 and set the default input to mic-in
3858 */
3859 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
3860 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3861 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
3862 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3863 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
3864 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3865
3866 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
3867 * mixer widget
3868 * Note: PASD motherboards uses the Line In 2 as the input for front panel
3869 * mic (mic 2)
3870 */
3871 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
3872 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3873 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3874 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
3875 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
3876 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
3877
3878 /*
3879 * Set up output mixers (0x0c - 0x0f)
3880 */
3881 /* set vol=0 to output mixers */
3882 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3883 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3884 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3885 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3886 /* set up input amps for analog loopback */
3887 /* Amp Indices: DAC = 0, mixer = 1 */
3888 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3889 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3890 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3891 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3892 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3893 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3894 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3895 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3896 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3897 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3898
3899 /* FIXME: use matrix-type input source selection */
3900 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
3901 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
3902 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3903 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
3904 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
3905 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
3906 /* Input mixer2 */
3907 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3908 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
3909 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
3910 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
3911 /* Input mixer3 */
3912 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3913 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
3914 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
3915 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
3916
3917 { }
3918};
3919
3920/* capture mixer elements */
3921static struct snd_kcontrol_new alc882_capture_alt_mixer[] = {
3922 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
3923 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
3924 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
3925 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
3926 {
3927 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3928 /* The multiple "Capture Source" controls confuse alsamixer
3929 * So call somewhat different..
3930 * FIXME: the controls appear in the "playback" view!
3931 */
3932 /* .name = "Capture Source", */
3933 .name = "Input Source",
3934 .count = 2,
3935 .info = alc882_mux_enum_info,
3936 .get = alc882_mux_enum_get,
3937 .put = alc882_mux_enum_put,
3938 },
3939 { } /* end */
3940};
3941
3942static struct snd_kcontrol_new alc882_capture_mixer[] = {
3943 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
3944 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
3945 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
3946 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
3947 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
3948 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
3949 {
3950 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3951 /* The multiple "Capture Source" controls confuse alsamixer
3952 * So call somewhat different..
3953 * FIXME: the controls appear in the "playback" view!
3954 */
3955 /* .name = "Capture Source", */
3956 .name = "Input Source",
3957 .count = 3,
3958 .info = alc882_mux_enum_info,
3959 .get = alc882_mux_enum_get,
3960 .put = alc882_mux_enum_put,
3961 },
3962 { } /* end */
3963};
3964
3965/* pcm configuration: identiacal with ALC880 */
3966#define alc882_pcm_analog_playback alc880_pcm_analog_playback
3967#define alc882_pcm_analog_capture alc880_pcm_analog_capture
3968#define alc882_pcm_digital_playback alc880_pcm_digital_playback
3969#define alc882_pcm_digital_capture alc880_pcm_digital_capture
3970
3971/*
3972 * configuration and preset
3973 */
3974static struct hda_board_config alc882_cfg_tbl[] = {
Takashi Iwai1494a922006-01-31 10:58:46 +01003975 { .modelname = "3stack-dig", .config = ALC882_3ST_DIG },
3976 { .modelname = "6stack-dig", .config = ALC882_6ST_DIG },
Kailang Yangdf694da2005-12-05 19:42:22 +01003977 { .pci_subvendor = 0x1462, .pci_subdevice = 0x6668, .config = ALC882_6ST_DIG }, /* MSI */
3978 { .pci_subvendor = 0x105b, .pci_subdevice = 0x6668, .config = ALC882_6ST_DIG }, /* Foxconn */
3979 { .pci_subvendor = 0x1019, .pci_subdevice = 0x6668, .config = ALC882_6ST_DIG }, /* ECS */
Takashi Iwai1494a922006-01-31 10:58:46 +01003980 { .modelname = "auto", .config = ALC882_AUTO },
Kailang Yangdf694da2005-12-05 19:42:22 +01003981 {}
3982};
3983
3984static struct alc_config_preset alc882_presets[] = {
3985 [ALC882_3ST_DIG] = {
3986 .mixers = { alc882_base_mixer },
3987 .init_verbs = { alc882_init_verbs },
3988 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
3989 .dac_nids = alc882_dac_nids,
3990 .dig_out_nid = ALC882_DIGOUT_NID,
3991 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
3992 .adc_nids = alc882_adc_nids,
3993 .dig_in_nid = ALC882_DIGIN_NID,
3994 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
3995 .channel_mode = alc882_ch_modes,
3996 .input_mux = &alc882_capture_source,
3997 },
3998 [ALC882_6ST_DIG] = {
3999 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
4000 .init_verbs = { alc882_init_verbs },
4001 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
4002 .dac_nids = alc882_dac_nids,
4003 .dig_out_nid = ALC882_DIGOUT_NID,
4004 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
4005 .adc_nids = alc882_adc_nids,
4006 .dig_in_nid = ALC882_DIGIN_NID,
4007 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
4008 .channel_mode = alc882_sixstack_modes,
4009 .input_mux = &alc882_capture_source,
4010 },
4011};
4012
4013
4014/*
4015 * BIOS auto configuration
4016 */
4017static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
4018 hda_nid_t nid, int pin_type,
4019 int dac_idx)
4020{
4021 /* set as output */
4022 struct alc_spec *spec = codec->spec;
4023 int idx;
4024
4025 if (spec->multiout.dac_nids[dac_idx] == 0x25)
4026 idx = 4;
4027 else
4028 idx = spec->multiout.dac_nids[dac_idx] - 2;
4029
4030 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
4031 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
4032 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
4033
4034}
4035
4036static void alc882_auto_init_multi_out(struct hda_codec *codec)
4037{
4038 struct alc_spec *spec = codec->spec;
4039 int i;
4040
4041 for (i = 0; i <= HDA_SIDE; i++) {
4042 hda_nid_t nid = spec->autocfg.line_out_pins[i];
4043 if (nid)
4044 alc882_auto_set_output_and_unmute(codec, nid, PIN_OUT, i);
4045 }
4046}
4047
4048static void alc882_auto_init_hp_out(struct hda_codec *codec)
4049{
4050 struct alc_spec *spec = codec->spec;
4051 hda_nid_t pin;
4052
4053 pin = spec->autocfg.hp_pin;
4054 if (pin) /* connect to front */
4055 alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); /* use dac 0 */
4056}
4057
4058#define alc882_is_input_pin(nid) alc880_is_input_pin(nid)
4059#define ALC882_PIN_CD_NID ALC880_PIN_CD_NID
4060
4061static void alc882_auto_init_analog_input(struct hda_codec *codec)
4062{
4063 struct alc_spec *spec = codec->spec;
4064 int i;
4065
4066 for (i = 0; i < AUTO_PIN_LAST; i++) {
4067 hda_nid_t nid = spec->autocfg.input_pins[i];
4068 if (alc882_is_input_pin(nid)) {
4069 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4070 i <= AUTO_PIN_FRONT_MIC ? PIN_VREF80 : PIN_IN);
4071 if (nid != ALC882_PIN_CD_NID)
4072 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
4073 AMP_OUT_MUTE);
4074 }
4075 }
4076}
4077
4078/* almost identical with ALC880 parser... */
4079static int alc882_parse_auto_config(struct hda_codec *codec)
4080{
4081 struct alc_spec *spec = codec->spec;
4082 int err = alc880_parse_auto_config(codec);
4083
4084 if (err < 0)
4085 return err;
Takashi Iwaic5f2ea02005-12-06 18:54:31 +01004086 else if (err > 0)
4087 /* hack - override the init verbs */
4088 spec->init_verbs[0] = alc882_auto_init_verbs;
4089 return err;
Kailang Yangdf694da2005-12-05 19:42:22 +01004090}
4091
4092/* init callback for auto-configuration model -- overriding the default init */
4093static int alc882_auto_init(struct hda_codec *codec)
4094{
4095 alc_init(codec);
4096 alc882_auto_init_multi_out(codec);
4097 alc882_auto_init_hp_out(codec);
4098 alc882_auto_init_analog_input(codec);
4099 return 0;
4100}
4101
4102/*
4103 * ALC882 Headphone poll in 3.5.1a or 3.5.2
4104 */
4105
Linus Torvalds1da177e2005-04-16 15:20:36 -07004106static int patch_alc882(struct hda_codec *codec)
4107{
4108 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01004109 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004110
Takashi Iwaie560d8d2005-09-09 14:21:46 +02004111 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004112 if (spec == NULL)
4113 return -ENOMEM;
4114
Linus Torvalds1da177e2005-04-16 15:20:36 -07004115 codec->spec = spec;
4116
Kailang Yangdf694da2005-12-05 19:42:22 +01004117 board_config = snd_hda_check_board_config(codec, alc882_cfg_tbl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004118
Kailang Yangdf694da2005-12-05 19:42:22 +01004119 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
4120 printk(KERN_INFO "hda_codec: Unknown model for ALC882, trying auto-probe from BIOS...\n");
4121 board_config = ALC882_AUTO;
4122 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004123
Kailang Yangdf694da2005-12-05 19:42:22 +01004124 if (board_config == ALC882_AUTO) {
4125 /* automatic parse from the BIOS config */
4126 err = alc882_parse_auto_config(codec);
4127 if (err < 0) {
4128 alc_free(codec);
4129 return err;
4130 } else if (! err) {
4131 printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using base mode...\n");
4132 board_config = ALC882_3ST_DIG;
4133 }
4134 }
4135
4136 if (board_config != ALC882_AUTO)
4137 setup_preset(spec, &alc882_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138
4139 spec->stream_name_analog = "ALC882 Analog";
Kailang Yangdf694da2005-12-05 19:42:22 +01004140 spec->stream_analog_playback = &alc882_pcm_analog_playback;
4141 spec->stream_analog_capture = &alc882_pcm_analog_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004142
4143 spec->stream_name_digital = "ALC882 Digital";
Kailang Yangdf694da2005-12-05 19:42:22 +01004144 spec->stream_digital_playback = &alc882_pcm_digital_playback;
4145 spec->stream_digital_capture = &alc882_pcm_digital_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004146
Kailang Yangdf694da2005-12-05 19:42:22 +01004147 if (! spec->adc_nids && spec->input_mux) {
4148 /* check whether NID 0x07 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +01004149 unsigned int wcap = get_wcaps(codec, 0x07);
Kailang Yangdf694da2005-12-05 19:42:22 +01004150 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */
4151 if (wcap != AC_WID_AUD_IN) {
4152 spec->adc_nids = alc882_adc_nids_alt;
4153 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids_alt);
4154 spec->mixers[spec->num_mixers] = alc882_capture_alt_mixer;
4155 spec->num_mixers++;
4156 } else {
4157 spec->adc_nids = alc882_adc_nids;
4158 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids);
4159 spec->mixers[spec->num_mixers] = alc882_capture_mixer;
4160 spec->num_mixers++;
4161 }
4162 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163
4164 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01004165 if (board_config == ALC882_AUTO)
4166 codec->patch_ops.init = alc882_auto_init;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004167
4168 return 0;
4169}
4170
4171/*
Kailang Yangdf694da2005-12-05 19:42:22 +01004172 * ALC262 support
4173 */
4174
4175#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID
4176#define ALC262_DIGIN_NID ALC880_DIGIN_NID
4177
4178#define alc262_dac_nids alc260_dac_nids
4179#define alc262_adc_nids alc882_adc_nids
4180#define alc262_adc_nids_alt alc882_adc_nids_alt
4181
4182#define alc262_modes alc260_modes
Takashi Iwaic5f2ea02005-12-06 18:54:31 +01004183#define alc262_capture_source alc882_capture_source
Kailang Yangdf694da2005-12-05 19:42:22 +01004184
4185static struct snd_kcontrol_new alc262_base_mixer[] = {
4186 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
4187 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
4188 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
4189 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
4190 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
4191 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
4192 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
4193 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
4194 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
4195 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
4196 /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
4197 HDA_CODEC_MUTE("PC Beelp Playback Switch", 0x0b, 0x05, HDA_INPUT), */
4198 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
4199 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
4200 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
4201 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01004202 { } /* end */
Takashi Iwai834be882006-03-01 14:16:17 +01004203};
4204
Kailang Yangdf694da2005-12-05 19:42:22 +01004205#define alc262_capture_mixer alc882_capture_mixer
4206#define alc262_capture_alt_mixer alc882_capture_alt_mixer
4207
4208/*
4209 * generic initialization of ADC, input mixers and output mixers
4210 */
4211static struct hda_verb alc262_init_verbs[] = {
4212 /*
4213 * Unmute ADC0-2 and set the default input to mic-in
4214 */
4215 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
4216 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4217 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
4218 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4219 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
4220 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4221
4222 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
4223 * mixer widget
4224 * Note: PASD motherboards uses the Line In 2 as the input for front panel
4225 * mic (mic 2)
4226 */
4227 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
4228 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4229 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4230 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
4231 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
4232 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
4233
4234 /*
4235 * Set up output mixers (0x0c - 0x0e)
4236 */
4237 /* set vol=0 to output mixers */
4238 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4239 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4240 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4241 /* set up input amps for analog loopback */
4242 /* Amp Indices: DAC = 0, mixer = 1 */
4243 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4244 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4245 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4246 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4247 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4248 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4249
4250 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4251 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
4252 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4253 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4254 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4255 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4256
4257 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
4258 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
4259 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
4260 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
4261 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
4262
4263 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
4264 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
4265
4266 /* FIXME: use matrix-type input source selection */
4267 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
4268 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
4269 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4270 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
4271 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
4272 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
4273 /* Input mixer2 */
4274 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4275 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
4276 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
4277 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
4278 /* Input mixer3 */
4279 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4280 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
4281 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
4282 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
4283
4284 { }
4285};
4286
Takashi Iwai834be882006-03-01 14:16:17 +01004287/*
4288 * fujitsu model
4289 * 0x14 = headphone/spdif-out, 0x15 = internal speaker
4290 */
4291
4292#define ALC_HP_EVENT 0x37
4293
4294static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
4295 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
4296 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4297 {}
4298};
4299
4300static struct hda_input_mux alc262_fujitsu_capture_source = {
4301 .num_items = 2,
4302 .items = {
4303 { "Mic", 0x0 },
4304 { "CD", 0x4 },
4305 },
4306};
4307
4308/* mute/unmute internal speaker according to the hp jack and mute state */
4309static void alc262_fujitsu_automute(struct hda_codec *codec, int force)
4310{
4311 struct alc_spec *spec = codec->spec;
4312 unsigned int mute;
4313
4314 if (force || ! spec->sense_updated) {
4315 unsigned int present;
4316 /* need to execute and sync at first */
4317 snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
4318 present = snd_hda_codec_read(codec, 0x14, 0,
4319 AC_VERB_GET_PIN_SENSE, 0);
4320 spec->jack_present = (present & 0x80000000) != 0;
4321 spec->sense_updated = 1;
4322 }
4323 if (spec->jack_present) {
4324 /* mute internal speaker */
4325 snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0,
4326 0x80, 0x80);
4327 snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0,
4328 0x80, 0x80);
4329 } else {
4330 /* unmute internal speaker if necessary */
4331 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
4332 snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0,
4333 0x80, mute & 0x80);
4334 mute = snd_hda_codec_amp_read(codec, 0x14, 1, HDA_OUTPUT, 0);
4335 snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0,
4336 0x80, mute & 0x80);
4337 }
4338}
4339
4340/* unsolicited event for HP jack sensing */
4341static void alc262_fujitsu_unsol_event(struct hda_codec *codec,
4342 unsigned int res)
4343{
4344 if ((res >> 26) != ALC_HP_EVENT)
4345 return;
4346 alc262_fujitsu_automute(codec, 1);
4347}
4348
4349/* bind volumes of both NID 0x0c and 0x0d */
4350static int alc262_fujitsu_master_vol_put(struct snd_kcontrol *kcontrol,
4351 struct snd_ctl_elem_value *ucontrol)
4352{
4353 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4354 long *valp = ucontrol->value.integer.value;
4355 int change;
4356
4357 change = snd_hda_codec_amp_update(codec, 0x0c, 0, HDA_OUTPUT, 0,
4358 0x7f, valp[0] & 0x7f);
4359 change |= snd_hda_codec_amp_update(codec, 0x0c, 1, HDA_OUTPUT, 0,
4360 0x7f, valp[1] & 0x7f);
4361 snd_hda_codec_amp_update(codec, 0x0d, 0, HDA_OUTPUT, 0,
4362 0x7f, valp[0] & 0x7f);
4363 snd_hda_codec_amp_update(codec, 0x0d, 1, HDA_OUTPUT, 0,
4364 0x7f, valp[1] & 0x7f);
4365 return change;
4366}
4367
4368/* bind hp and internal speaker mute (with plug check) */
4369static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
4370 struct snd_ctl_elem_value *ucontrol)
4371{
4372 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4373 long *valp = ucontrol->value.integer.value;
4374 int change;
4375
4376 change = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
4377 0x80, valp[0] ? 0 : 0x80);
4378 change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
4379 0x80, valp[1] ? 0 : 0x80);
4380 if (change || codec->in_resume)
4381 alc262_fujitsu_automute(codec, codec->in_resume);
4382 return change;
4383}
4384
4385static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
4386 {
4387 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4388 .name = "Master Playback Volume",
4389 .info = snd_hda_mixer_amp_volume_info,
4390 .get = snd_hda_mixer_amp_volume_get,
4391 .put = alc262_fujitsu_master_vol_put,
4392 .private_value = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
4393 },
4394 {
4395 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4396 .name = "Master Playback Switch",
4397 .info = snd_hda_mixer_amp_switch_info,
4398 .get = snd_hda_mixer_amp_switch_get,
4399 .put = alc262_fujitsu_master_sw_put,
4400 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
4401 },
4402 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
4403 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
4404 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
4405 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
4406 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
4407 { } /* end */
4408};
4409
Kailang Yangdf694da2005-12-05 19:42:22 +01004410/* add playback controls from the parsed DAC table */
4411static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg)
4412{
4413 hda_nid_t nid;
4414 int err;
4415
4416 spec->multiout.num_dacs = 1; /* only use one dac */
4417 spec->multiout.dac_nids = spec->private_dac_nids;
4418 spec->multiout.dac_nids[0] = 2;
4419
4420 nid = cfg->line_out_pins[0];
4421 if (nid) {
4422 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Front Playback Volume",
4423 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT))) < 0)
4424 return err;
4425 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Front Playback Switch",
4426 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
4427 return err;
4428 }
4429
4430 nid = cfg->speaker_pin;
4431 if (nid) {
4432 if (nid == 0x16) {
4433 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Speaker Playback Volume",
4434 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT))) < 0)
4435 return err;
4436 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Speaker Playback Switch",
4437 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0)
4438 return err;
4439 } else {
4440 if (! cfg->line_out_pins[0])
4441 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Speaker Playback Volume",
4442 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT))) < 0)
4443 return err;
4444 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Speaker Playback Switch",
4445 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
4446 return err;
4447 }
4448 }
4449 nid = cfg->hp_pin;
4450 if (nid) {
4451 /* spec->multiout.hp_nid = 2; */
4452 if (nid == 0x16) {
4453 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Headphone Playback Volume",
4454 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT))) < 0)
4455 return err;
4456 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Headphone Playback Switch",
4457 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0)
4458 return err;
4459 } else {
4460 if (! cfg->line_out_pins[0])
4461 if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Headphone Playback Volume",
4462 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT))) < 0)
4463 return err;
4464 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Headphone Playback Switch",
4465 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
4466 return err;
4467 }
4468 }
4469 return 0;
4470}
4471
4472/* identical with ALC880 */
4473#define alc262_auto_create_analog_input_ctls alc880_auto_create_analog_input_ctls
4474
4475/*
4476 * generic initialization of ADC, input mixers and output mixers
4477 */
4478static struct hda_verb alc262_volume_init_verbs[] = {
4479 /*
4480 * Unmute ADC0-2 and set the default input to mic-in
4481 */
4482 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
4483 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4484 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
4485 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4486 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
4487 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4488
4489 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
4490 * mixer widget
4491 * Note: PASD motherboards uses the Line In 2 as the input for front panel
4492 * mic (mic 2)
4493 */
4494 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
4495 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4496 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4497 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
4498 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
4499 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
4500
4501 /*
4502 * Set up output mixers (0x0c - 0x0f)
4503 */
4504 /* set vol=0 to output mixers */
4505 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4506 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4507 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4508
4509 /* set up input amps for analog loopback */
4510 /* Amp Indices: DAC = 0, mixer = 1 */
4511 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4512 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4513 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4514 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4515 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4516 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4517
4518 /* FIXME: use matrix-type input source selection */
4519 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
4520 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
4521 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4522 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
4523 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
4524 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
4525 /* Input mixer2 */
4526 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4527 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
4528 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
4529 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
4530 /* Input mixer3 */
4531 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4532 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
4533 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
4534 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
4535
4536 { }
4537};
4538
4539/* pcm configuration: identiacal with ALC880 */
4540#define alc262_pcm_analog_playback alc880_pcm_analog_playback
4541#define alc262_pcm_analog_capture alc880_pcm_analog_capture
4542#define alc262_pcm_digital_playback alc880_pcm_digital_playback
4543#define alc262_pcm_digital_capture alc880_pcm_digital_capture
4544
4545/*
4546 * BIOS auto configuration
4547 */
4548static int alc262_parse_auto_config(struct hda_codec *codec)
4549{
4550 struct alc_spec *spec = codec->spec;
4551 int err;
4552 static hda_nid_t alc262_ignore[] = { 0x1d, 0 };
4553
4554 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
4555 alc262_ignore)) < 0)
4556 return err;
4557 if (! spec->autocfg.line_outs && ! spec->autocfg.speaker_pin &&
4558 ! spec->autocfg.hp_pin)
4559 return 0; /* can't find valid BIOS pin config */
4560 if ((err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 ||
4561 (err = alc262_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
4562 return err;
4563
4564 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
4565
4566 if (spec->autocfg.dig_out_pin)
4567 spec->multiout.dig_out_nid = ALC262_DIGOUT_NID;
4568 if (spec->autocfg.dig_in_pin)
4569 spec->dig_in_nid = ALC262_DIGIN_NID;
4570
4571 if (spec->kctl_alloc)
4572 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
4573
4574 spec->init_verbs[spec->num_init_verbs++] = alc262_volume_init_verbs;
4575 spec->input_mux = &spec->private_imux;
4576
4577 return 1;
4578}
4579
4580#define alc262_auto_init_multi_out alc882_auto_init_multi_out
4581#define alc262_auto_init_hp_out alc882_auto_init_hp_out
4582#define alc262_auto_init_analog_input alc882_auto_init_analog_input
4583
4584
4585/* init callback for auto-configuration model -- overriding the default init */
4586static int alc262_auto_init(struct hda_codec *codec)
4587{
4588 alc_init(codec);
4589 alc262_auto_init_multi_out(codec);
4590 alc262_auto_init_hp_out(codec);
4591 alc262_auto_init_analog_input(codec);
4592 return 0;
4593}
4594
4595/*
4596 * configuration and preset
4597 */
4598static struct hda_board_config alc262_cfg_tbl[] = {
4599 { .modelname = "basic", .config = ALC262_BASIC },
Takashi Iwai834be882006-03-01 14:16:17 +01004600 { .modelname = "fujitsu", .config = ALC262_FUJITSU },
4601 { .pci_subvendor = 0x10cf, .pci_subdevice = 0x1397, .config = ALC262_FUJITSU },
Kailang Yangdf694da2005-12-05 19:42:22 +01004602 { .modelname = "auto", .config = ALC262_AUTO },
4603 {}
4604};
4605
4606static struct alc_config_preset alc262_presets[] = {
4607 [ALC262_BASIC] = {
4608 .mixers = { alc262_base_mixer },
4609 .init_verbs = { alc262_init_verbs },
4610 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
4611 .dac_nids = alc262_dac_nids,
4612 .hp_nid = 0x03,
4613 .num_channel_mode = ARRAY_SIZE(alc262_modes),
4614 .channel_mode = alc262_modes,
Takashi Iwaia3bcba32005-12-06 19:05:29 +01004615 .input_mux = &alc262_capture_source,
Kailang Yangdf694da2005-12-05 19:42:22 +01004616 },
Takashi Iwai834be882006-03-01 14:16:17 +01004617 [ALC262_FUJITSU] = {
4618 .mixers = { alc262_fujitsu_mixer },
4619 .init_verbs = { alc262_init_verbs, alc262_fujitsu_unsol_verbs },
4620 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
4621 .dac_nids = alc262_dac_nids,
4622 .hp_nid = 0x03,
4623 .dig_out_nid = ALC262_DIGOUT_NID,
4624 .num_channel_mode = ARRAY_SIZE(alc262_modes),
4625 .channel_mode = alc262_modes,
4626 .input_mux = &alc262_fujitsu_capture_source,
4627 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004628};
4629
4630static int patch_alc262(struct hda_codec *codec)
4631{
4632 struct alc_spec *spec;
4633 int board_config;
4634 int err;
4635
4636 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
4637 if (spec == NULL)
4638 return -ENOMEM;
4639
4640 codec->spec = spec;
4641#if 0
4642 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is under-run */
4643 {
4644 int tmp;
4645 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
4646 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
4647 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
4648 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
4649 }
4650#endif
4651
4652 board_config = snd_hda_check_board_config(codec, alc262_cfg_tbl);
4653 if (board_config < 0 || board_config >= ALC262_MODEL_LAST) {
4654 printk(KERN_INFO "hda_codec: Unknown model for ALC262, trying auto-probe from BIOS...\n");
4655 board_config = ALC262_AUTO;
4656 }
4657
4658 if (board_config == ALC262_AUTO) {
4659 /* automatic parse from the BIOS config */
4660 err = alc262_parse_auto_config(codec);
4661 if (err < 0) {
4662 alc_free(codec);
4663 return err;
4664 } else if (! err) {
4665 printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using base mode...\n");
4666 board_config = ALC262_BASIC;
4667 }
4668 }
4669
4670 if (board_config != ALC262_AUTO)
4671 setup_preset(spec, &alc262_presets[board_config]);
4672
4673 spec->stream_name_analog = "ALC262 Analog";
4674 spec->stream_analog_playback = &alc262_pcm_analog_playback;
4675 spec->stream_analog_capture = &alc262_pcm_analog_capture;
4676
4677 spec->stream_name_digital = "ALC262 Digital";
4678 spec->stream_digital_playback = &alc262_pcm_digital_playback;
4679 spec->stream_digital_capture = &alc262_pcm_digital_capture;
4680
4681 if (! spec->adc_nids && spec->input_mux) {
4682 /* check whether NID 0x07 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +01004683 unsigned int wcap = get_wcaps(codec, 0x07);
4684
Kailang Yangdf694da2005-12-05 19:42:22 +01004685 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */
4686 if (wcap != AC_WID_AUD_IN) {
4687 spec->adc_nids = alc262_adc_nids_alt;
4688 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids_alt);
4689 spec->mixers[spec->num_mixers] = alc262_capture_alt_mixer;
4690 spec->num_mixers++;
4691 } else {
4692 spec->adc_nids = alc262_adc_nids;
4693 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids);
4694 spec->mixers[spec->num_mixers] = alc262_capture_mixer;
4695 spec->num_mixers++;
4696 }
4697 }
4698
4699 codec->patch_ops = alc_patch_ops;
4700 if (board_config == ALC262_AUTO)
4701 codec->patch_ops.init = alc262_auto_init;
Takashi Iwai834be882006-03-01 14:16:17 +01004702 if (board_config == ALC262_FUJITSU)
4703 codec->patch_ops.unsol_event = alc262_fujitsu_unsol_event;
4704
Kailang Yangdf694da2005-12-05 19:42:22 +01004705 return 0;
4706}
4707
4708
4709/*
4710 * ALC861 channel source setting (2/6 channel selection for 3-stack)
4711 */
4712
4713/*
4714 * set the path ways for 2 channel output
4715 * need to set the codec line out and mic 1 pin widgets to inputs
4716 */
4717static struct hda_verb alc861_threestack_ch2_init[] = {
4718 /* set pin widget 1Ah (line in) for input */
4719 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
4720 /* set pin widget 18h (mic1/2) for input, for mic also enable the vref */
4721 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
4722
4723 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
4724 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, //mic
4725 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, //line in
4726 { } /* end */
4727};
4728/*
4729 * 6ch mode
4730 * need to set the codec line out and mic 1 pin widgets to outputs
4731 */
4732static struct hda_verb alc861_threestack_ch6_init[] = {
4733 /* set pin widget 1Ah (line in) for output (Back Surround)*/
4734 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
4735 /* set pin widget 18h (mic1) for output (CLFE)*/
4736 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
4737
4738 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
4739 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
4740
4741 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
4742 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, //mic
4743 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, //line in
4744 { } /* end */
4745};
4746
4747static struct hda_channel_mode alc861_threestack_modes[2] = {
4748 { 2, alc861_threestack_ch2_init },
4749 { 6, alc861_threestack_ch6_init },
4750};
4751
4752/* patch-ALC861 */
4753
4754static struct snd_kcontrol_new alc861_base_mixer[] = {
4755 /* output mixer control */
4756 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
4757 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
4758 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
4759 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
4760 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
4761
4762 /*Input mixer control */
4763 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
4764 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
4765 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
4766 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
4767 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
4768 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
4769 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
4770 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
4771 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
4772 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
4773
4774 /* Capture mixer control */
4775 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
4776 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
4777 {
4778 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4779 .name = "Capture Source",
4780 .count = 1,
4781 .info = alc_mux_enum_info,
4782 .get = alc_mux_enum_get,
4783 .put = alc_mux_enum_put,
4784 },
4785 { } /* end */
4786};
4787
4788static struct snd_kcontrol_new alc861_3ST_mixer[] = {
4789 /* output mixer control */
4790 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
4791 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
4792 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
4793 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
4794 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
4795
4796 /* Input mixer control */
4797 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
4798 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
4799 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
4800 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
4801 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
4802 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
4803 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
4804 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
4805 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
4806 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
4807
4808 /* Capture mixer control */
4809 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
4810 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
4811 {
4812 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4813 .name = "Capture Source",
4814 .count = 1,
4815 .info = alc_mux_enum_info,
4816 .get = alc_mux_enum_get,
4817 .put = alc_mux_enum_put,
4818 },
4819 {
4820 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4821 .name = "Channel Mode",
4822 .info = alc_ch_mode_info,
4823 .get = alc_ch_mode_get,
4824 .put = alc_ch_mode_put,
4825 .private_value = ARRAY_SIZE(alc861_threestack_modes),
4826 },
4827 { } /* end */
4828};
4829
4830/*
4831 * generic initialization of ADC, input mixers and output mixers
4832 */
4833static struct hda_verb alc861_base_init_verbs[] = {
4834 /*
4835 * Unmute ADC0 and set the default input to mic-in
4836 */
4837 /* port-A for surround (rear panel) */
4838 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
4839 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
4840 /* port-B for mic-in (rear panel) with vref */
4841 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
4842 /* port-C for line-in (rear panel) */
4843 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
4844 /* port-D for Front */
4845 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
4846 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
4847 /* port-E for HP out (front panel) */
4848 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
4849 /* route front PCM to HP */
4850 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01 },
4851 /* port-F for mic-in (front panel) with vref */
4852 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
4853 /* port-G for CLFE (rear panel) */
4854 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
4855 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
4856 /* port-H for side (rear panel) */
4857 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
4858 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
4859 /* CD-in */
4860 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
4861 /* route front mic to ADC1*/
4862 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
4863 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4864
4865 /* Unmute DAC0~3 & spdif out*/
4866 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4867 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4868 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4869 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4870 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4871
4872 /* Unmute Mixer 14 (mic) 1c (Line in)*/
4873 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4874 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4875 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4876 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4877
4878 /* Unmute Stereo Mixer 15 */
4879 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4880 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4881 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
4882 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c }, //Output 0~12 step
4883
4884 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4885 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4886 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4887 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4888 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4889 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4890 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4891 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4892 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, // hp used DAC 3 (Front)
4893 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
4894
4895 { }
4896};
4897
4898static struct hda_verb alc861_threestack_init_verbs[] = {
4899 /*
4900 * Unmute ADC0 and set the default input to mic-in
4901 */
4902 /* port-A for surround (rear panel) */
4903 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
4904 /* port-B for mic-in (rear panel) with vref */
4905 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
4906 /* port-C for line-in (rear panel) */
4907 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
4908 /* port-D for Front */
4909 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
4910 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
4911 /* port-E for HP out (front panel) */
4912 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
4913 /* route front PCM to HP */
4914 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01 },
4915 /* port-F for mic-in (front panel) with vref */
4916 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
4917 /* port-G for CLFE (rear panel) */
4918 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
4919 /* port-H for side (rear panel) */
4920 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
4921 /* CD-in */
4922 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
4923 /* route front mic to ADC1*/
4924 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
4925 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4926 /* Unmute DAC0~3 & spdif out*/
4927 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4928 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4929 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4930 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4931 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4932
4933 /* Unmute Mixer 14 (mic) 1c (Line in)*/
4934 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4935 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4936 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4937 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4938
4939 /* Unmute Stereo Mixer 15 */
4940 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4941 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4942 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
4943 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c }, //Output 0~12 step
4944
4945 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4946 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4947 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4948 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4949 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4950 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4951 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4952 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4953 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, // hp used DAC 3 (Front)
4954 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
4955 { }
4956};
4957/*
4958 * generic initialization of ADC, input mixers and output mixers
4959 */
4960static struct hda_verb alc861_auto_init_verbs[] = {
4961 /*
4962 * Unmute ADC0 and set the default input to mic-in
4963 */
4964// {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
4965 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4966
4967 /* Unmute DAC0~3 & spdif out*/
4968 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4969 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4970 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4971 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4972 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4973
4974 /* Unmute Mixer 14 (mic) 1c (Line in)*/
4975 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4976 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4977 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4978 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4979
4980 /* Unmute Stereo Mixer 15 */
4981 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4982 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4983 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
4984 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
4985
4986 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4987 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4988 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4989 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4990 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4991 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4992 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4993 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4994
4995 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4996 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4997 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
4998 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
4999 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5000 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5001 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
5002 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
5003
5004 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, // set Mic 1
5005
5006 { }
5007};
5008
5009/* pcm configuration: identiacal with ALC880 */
5010#define alc861_pcm_analog_playback alc880_pcm_analog_playback
5011#define alc861_pcm_analog_capture alc880_pcm_analog_capture
5012#define alc861_pcm_digital_playback alc880_pcm_digital_playback
5013#define alc861_pcm_digital_capture alc880_pcm_digital_capture
5014
5015
5016#define ALC861_DIGOUT_NID 0x07
5017
5018static struct hda_channel_mode alc861_8ch_modes[1] = {
5019 { 8, NULL }
5020};
5021
5022static hda_nid_t alc861_dac_nids[4] = {
5023 /* front, surround, clfe, side */
5024 0x03, 0x06, 0x05, 0x04
5025};
5026
5027static hda_nid_t alc861_adc_nids[1] = {
5028 /* ADC0-2 */
5029 0x08,
5030};
5031
5032static struct hda_input_mux alc861_capture_source = {
5033 .num_items = 5,
5034 .items = {
5035 { "Mic", 0x0 },
5036 { "Front Mic", 0x3 },
5037 { "Line", 0x1 },
5038 { "CD", 0x4 },
5039 { "Mixer", 0x5 },
5040 },
5041};
5042
5043/* fill in the dac_nids table from the parsed pin configuration */
5044static int alc861_auto_fill_dac_nids(struct alc_spec *spec, const struct auto_pin_cfg *cfg)
5045{
5046 int i;
5047 hda_nid_t nid;
5048
5049 spec->multiout.dac_nids = spec->private_dac_nids;
5050 for (i = 0; i < cfg->line_outs; i++) {
5051 nid = cfg->line_out_pins[i];
5052 if (nid) {
5053 if (i >= ARRAY_SIZE(alc861_dac_nids))
5054 continue;
5055 spec->multiout.dac_nids[i] = alc861_dac_nids[i];
5056 }
5057 }
5058 spec->multiout.num_dacs = cfg->line_outs;
5059 return 0;
5060}
5061
5062/* add playback controls from the parsed DAC table */
5063static int alc861_auto_create_multi_out_ctls(struct alc_spec *spec,
5064 const struct auto_pin_cfg *cfg)
5065{
5066 char name[32];
5067 static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" };
5068 hda_nid_t nid;
5069 int i, idx, err;
5070
5071 for (i = 0; i < cfg->line_outs; i++) {
5072 nid = spec->multiout.dac_nids[i];
5073 if (! nid)
5074 continue;
5075 if (nid == 0x05) {
5076 /* Center/LFE */
5077 if ((err = add_control(spec, ALC_CTL_BIND_MUTE, "Center Playback Switch",
5078 HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT))) < 0)
5079 return err;
5080 if ((err = add_control(spec, ALC_CTL_BIND_MUTE, "LFE Playback Switch",
5081 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0)
5082 return err;
5083 } else {
5084 for (idx = 0; idx < ARRAY_SIZE(alc861_dac_nids) - 1; idx++)
5085 if (nid == alc861_dac_nids[idx])
5086 break;
5087 sprintf(name, "%s Playback Switch", chname[idx]);
5088 if ((err = add_control(spec, ALC_CTL_BIND_MUTE, name,
5089 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
5090 return err;
5091 }
5092 }
5093 return 0;
5094}
5095
5096static int alc861_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin)
5097{
5098 int err;
5099 hda_nid_t nid;
5100
5101 if (! pin)
5102 return 0;
5103
5104 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
5105 nid = 0x03;
5106 if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Headphone Playback Switch",
5107 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
5108 return err;
5109 spec->multiout.hp_nid = nid;
5110 }
5111 return 0;
5112}
5113
5114/* create playback/capture controls for input pins */
5115static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg)
5116{
Kailang Yangdf694da2005-12-05 19:42:22 +01005117 struct hda_input_mux *imux = &spec->private_imux;
5118 int i, err, idx, idx1;
5119
5120 for (i = 0; i < AUTO_PIN_LAST; i++) {
5121 switch(cfg->input_pins[i]) {
5122 case 0x0c:
5123 idx1 = 1;
5124 idx = 2; // Line In
5125 break;
5126 case 0x0f:
5127 idx1 = 2;
5128 idx = 2; // Line In
5129 break;
5130 case 0x0d:
5131 idx1 = 0;
5132 idx = 1; // Mic In
5133 break;
5134 case 0x10:
5135 idx1 = 3;
5136 idx = 1; // Mic In
5137 break;
5138 case 0x11:
5139 idx1 = 4;
5140 idx = 0; // CD
5141 break;
5142 default:
5143 continue;
5144 }
5145
Takashi Iwai4a471b72005-12-07 13:56:29 +01005146 err = new_analog_input(spec, cfg->input_pins[i],
5147 auto_pin_cfg_labels[i], idx, 0x15);
Kailang Yangdf694da2005-12-05 19:42:22 +01005148 if (err < 0)
5149 return err;
5150
Takashi Iwai4a471b72005-12-07 13:56:29 +01005151 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +01005152 imux->items[imux->num_items].index = idx1;
5153 imux->num_items++;
5154 }
5155 return 0;
5156}
5157
5158static struct snd_kcontrol_new alc861_capture_mixer[] = {
5159 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
5160 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
5161
5162 {
5163 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5164 /* The multiple "Capture Source" controls confuse alsamixer
5165 * So call somewhat different..
5166 *FIXME: the controls appear in the "playback" view!
5167 */
5168 /* .name = "Capture Source", */
5169 .name = "Input Source",
5170 .count = 1,
5171 .info = alc_mux_enum_info,
5172 .get = alc_mux_enum_get,
5173 .put = alc_mux_enum_put,
5174 },
5175 { } /* end */
5176};
5177
5178static void alc861_auto_set_output_and_unmute(struct hda_codec *codec, hda_nid_t nid,
5179 int pin_type, int dac_idx)
5180{
5181 /* set as output */
5182
5183 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
5184 snd_hda_codec_write(codec, dac_idx, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
5185
5186}
5187
5188static void alc861_auto_init_multi_out(struct hda_codec *codec)
5189{
5190 struct alc_spec *spec = codec->spec;
5191 int i;
5192
5193 for (i = 0; i < spec->autocfg.line_outs; i++) {
5194 hda_nid_t nid = spec->autocfg.line_out_pins[i];
5195 if (nid)
5196 alc861_auto_set_output_and_unmute(codec, nid, PIN_OUT, spec->multiout.dac_nids[i]);
5197 }
5198}
5199
5200static void alc861_auto_init_hp_out(struct hda_codec *codec)
5201{
5202 struct alc_spec *spec = codec->spec;
5203 hda_nid_t pin;
5204
5205 pin = spec->autocfg.hp_pin;
5206 if (pin) /* connect to front */
5207 alc861_auto_set_output_and_unmute(codec, pin, PIN_HP, spec->multiout.dac_nids[0]);
5208}
5209
5210static void alc861_auto_init_analog_input(struct hda_codec *codec)
5211{
5212 struct alc_spec *spec = codec->spec;
5213 int i;
5214
5215 for (i = 0; i < AUTO_PIN_LAST; i++) {
5216 hda_nid_t nid = spec->autocfg.input_pins[i];
5217 if ((nid>=0x0c) && (nid <=0x11)) {
5218 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5219 i <= AUTO_PIN_FRONT_MIC ? PIN_VREF80 : PIN_IN);
5220 }
5221 }
5222}
5223
5224/* parse the BIOS configuration and set up the alc_spec */
5225/* return 1 if successful, 0 if the proper config is not found, or a negative error code */
5226static int alc861_parse_auto_config(struct hda_codec *codec)
5227{
5228 struct alc_spec *spec = codec->spec;
5229 int err;
5230 static hda_nid_t alc861_ignore[] = { 0x1d, 0 };
5231
5232 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
5233 alc861_ignore)) < 0)
5234 return err;
5235 if (! spec->autocfg.line_outs && ! spec->autocfg.speaker_pin &&
5236 ! spec->autocfg.hp_pin)
5237 return 0; /* can't find valid BIOS pin config */
5238
5239 if ((err = alc861_auto_fill_dac_nids(spec, &spec->autocfg)) < 0 ||
5240 (err = alc861_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 ||
5241 (err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pin)) < 0 ||
5242 (err = alc861_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
5243 return err;
5244
5245 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
5246
5247 if (spec->autocfg.dig_out_pin)
5248 spec->multiout.dig_out_nid = ALC861_DIGOUT_NID;
5249
5250 if (spec->kctl_alloc)
5251 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
5252
5253 spec->init_verbs[spec->num_init_verbs++] = alc861_auto_init_verbs;
5254
5255 spec->input_mux = &spec->private_imux;
5256
5257 spec->adc_nids = alc861_adc_nids;
5258 spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
5259 spec->mixers[spec->num_mixers] = alc861_capture_mixer;
5260 spec->num_mixers++;
5261
5262 return 1;
5263}
5264
5265/* init callback for auto-configuration model -- overriding the default init */
5266static int alc861_auto_init(struct hda_codec *codec)
5267{
5268 alc_init(codec);
5269 alc861_auto_init_multi_out(codec);
5270 alc861_auto_init_hp_out(codec);
5271 alc861_auto_init_analog_input(codec);
5272
5273 return 0;
5274}
5275
5276
5277/*
5278 * configuration and preset
5279 */
5280static struct hda_board_config alc861_cfg_tbl[] = {
5281 { .modelname = "3stack", .config = ALC861_3ST },
5282 { .pci_subvendor = 0x8086, .pci_subdevice = 0xd600, .config = ALC861_3ST },
5283 { .modelname = "3stack-dig", .config = ALC861_3ST_DIG },
5284 { .modelname = "6stack-dig", .config = ALC861_6ST_DIG },
5285 { .modelname = "auto", .config = ALC861_AUTO },
5286 {}
5287};
5288
5289static struct alc_config_preset alc861_presets[] = {
5290 [ALC861_3ST] = {
5291 .mixers = { alc861_3ST_mixer },
5292 .init_verbs = { alc861_threestack_init_verbs },
5293 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
5294 .dac_nids = alc861_dac_nids,
5295 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
5296 .channel_mode = alc861_threestack_modes,
5297 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
5298 .adc_nids = alc861_adc_nids,
5299 .input_mux = &alc861_capture_source,
5300 },
5301 [ALC861_3ST_DIG] = {
5302 .mixers = { alc861_base_mixer },
5303 .init_verbs = { alc861_threestack_init_verbs },
5304 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
5305 .dac_nids = alc861_dac_nids,
5306 .dig_out_nid = ALC861_DIGOUT_NID,
5307 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
5308 .channel_mode = alc861_threestack_modes,
5309 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
5310 .adc_nids = alc861_adc_nids,
5311 .input_mux = &alc861_capture_source,
5312 },
5313 [ALC861_6ST_DIG] = {
5314 .mixers = { alc861_base_mixer },
5315 .init_verbs = { alc861_base_init_verbs },
5316 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
5317 .dac_nids = alc861_dac_nids,
5318 .dig_out_nid = ALC861_DIGOUT_NID,
5319 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
5320 .channel_mode = alc861_8ch_modes,
5321 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
5322 .adc_nids = alc861_adc_nids,
5323 .input_mux = &alc861_capture_source,
5324 },
5325};
5326
5327
5328static int patch_alc861(struct hda_codec *codec)
5329{
5330 struct alc_spec *spec;
5331 int board_config;
5332 int err;
5333
5334 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
5335 if (spec == NULL)
5336 return -ENOMEM;
5337
5338 codec->spec = spec;
5339
5340 board_config = snd_hda_check_board_config(codec, alc861_cfg_tbl);
5341 if (board_config < 0 || board_config >= ALC861_MODEL_LAST) {
5342 printk(KERN_INFO "hda_codec: Unknown model for ALC861, trying auto-probe from BIOS...\n");
5343 board_config = ALC861_AUTO;
5344 }
5345
5346 if (board_config == ALC861_AUTO) {
5347 /* automatic parse from the BIOS config */
5348 err = alc861_parse_auto_config(codec);
5349 if (err < 0) {
5350 alc_free(codec);
5351 return err;
5352 } else if (! err) {
5353 printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using base mode...\n");
5354 board_config = ALC861_3ST_DIG;
5355 }
5356 }
5357
5358 if (board_config != ALC861_AUTO)
5359 setup_preset(spec, &alc861_presets[board_config]);
5360
5361 spec->stream_name_analog = "ALC861 Analog";
5362 spec->stream_analog_playback = &alc861_pcm_analog_playback;
5363 spec->stream_analog_capture = &alc861_pcm_analog_capture;
5364
5365 spec->stream_name_digital = "ALC861 Digital";
5366 spec->stream_digital_playback = &alc861_pcm_digital_playback;
5367 spec->stream_digital_capture = &alc861_pcm_digital_capture;
5368
5369 codec->patch_ops = alc_patch_ops;
5370 if (board_config == ALC861_AUTO)
5371 codec->patch_ops.init = alc861_auto_init;
5372
5373 return 0;
5374}
5375
5376/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07005377 * patch entries
5378 */
5379struct hda_codec_preset snd_hda_preset_realtek[] = {
5380 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +01005381 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07005382 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
5383 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Kailang Yangdf694da2005-12-05 19:42:22 +01005384 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 },
5385 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
5386 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07005387 {} /* terminator */
5388};