blob: 9aa2b5821e070f11c75dfdba4d5ac0c1841eefce [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 Woithe7cf51e482006-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
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/init.h>
27#include <linux/delay.h>
28#include <linux/slab.h>
29#include <linux/pci.h>
30#include <sound/core.h>
31#include "hda_codec.h"
32#include "hda_local.h"
33
Kailang Yangccc656c2006-10-17 12:32:26 +020034#define ALC880_FRONT_EVENT 0x01
35#define ALC880_DCVOL_EVENT 0x02
36#define ALC880_HP_EVENT 0x04
37#define ALC880_MIC_EVENT 0x08
Linus Torvalds1da177e2005-04-16 15:20:36 -070038
39/* ALC880 board config type */
40enum {
Linus Torvalds1da177e2005-04-16 15:20:36 -070041 ALC880_3ST,
42 ALC880_3ST_DIG,
43 ALC880_5ST,
44 ALC880_5ST_DIG,
45 ALC880_W810,
Takashi Iwaidfc0ff62005-05-12 14:31:49 +020046 ALC880_Z71V,
Takashi Iwaib6482d42005-06-27 15:32:43 +020047 ALC880_6ST,
Takashi Iwai16ded522005-06-10 19:58:24 +020048 ALC880_6ST_DIG,
49 ALC880_F1734,
50 ALC880_ASUS,
51 ALC880_ASUS_DIG,
52 ALC880_ASUS_W1V,
Kailang Yangdf694da2005-12-05 19:42:22 +010053 ALC880_ASUS_DIG2,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +010054 ALC880_FUJITSU,
Takashi Iwai16ded522005-06-10 19:58:24 +020055 ALC880_UNIWILL_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +020056 ALC880_UNIWILL,
57 ALC880_UNIWILL_P53,
Kailang Yangdf694da2005-12-05 19:42:22 +010058 ALC880_CLEVO,
59 ALC880_TCL_S700,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010060 ALC880_LG,
Takashi Iwaid6815182006-03-23 16:06:23 +010061 ALC880_LG_LW,
Takashi Iwaie9edcee2005-06-13 14:16:38 +020062#ifdef CONFIG_SND_DEBUG
63 ALC880_TEST,
64#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010065 ALC880_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020066 ALC880_MODEL_LAST /* last tag */
67};
68
69/* ALC260 models */
70enum {
71 ALC260_BASIC,
72 ALC260_HP,
Kailang Yangdf694da2005-12-05 19:42:22 +010073 ALC260_HP_3013,
74 ALC260_FUJITSU_S702X,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +010075 ALC260_ACER,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020076 ALC260_WILL,
77 ALC260_REPLACER_672V,
Jonathan Woithe7cf51e482006-02-09 12:01:26 +010078#ifdef CONFIG_SND_DEBUG
79 ALC260_TEST,
80#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010081 ALC260_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020082 ALC260_MODEL_LAST /* last tag */
Linus Torvalds1da177e2005-04-16 15:20:36 -070083};
84
Kailang Yangdf694da2005-12-05 19:42:22 +010085/* ALC262 models */
86enum {
87 ALC262_BASIC,
Kailang Yangccc656c2006-10-17 12:32:26 +020088 ALC262_HIPPO,
89 ALC262_HIPPO_1,
Takashi Iwai834be882006-03-01 14:16:17 +010090 ALC262_FUJITSU,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020091 ALC262_HP_BPC,
Kailang Yangcd7509a2007-01-26 18:33:17 +010092 ALC262_HP_BPC_D7000_WL,
93 ALC262_HP_BPC_D7000_WF,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010094 ALC262_HP_TC_T5735,
Kailang Yang8c427222008-01-10 13:03:59 +010095 ALC262_HP_RP5700,
Takashi Iwai304dcaa2006-07-25 14:51:16 +020096 ALC262_BENQ_ED8,
Kailang Yang272a5272007-05-14 11:00:38 +020097 ALC262_SONY_ASSAMD,
Kailang Yang83c34212007-07-05 11:43:05 +020098 ALC262_BENQ_T31,
Tobin Davisf651b502007-10-26 12:40:47 +020099 ALC262_ULTRA,
Kailang Yangdf694da2005-12-05 19:42:22 +0100100 ALC262_AUTO,
101 ALC262_MODEL_LAST /* last tag */
102};
103
Kailang Yanga361d842007-06-05 12:30:55 +0200104/* ALC268 models */
105enum {
106 ALC268_3ST,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200107 ALC268_TOSHIBA,
Takashi Iwaid2738092007-08-16 14:59:45 +0200108 ALC268_ACER,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +0100109#ifdef CONFIG_SND_DEBUG
110 ALC268_TEST,
111#endif
Kailang Yanga361d842007-06-05 12:30:55 +0200112 ALC268_AUTO,
113 ALC268_MODEL_LAST /* last tag */
114};
115
Kailang Yangf6a92242007-12-13 16:52:54 +0100116/* ALC269 models */
117enum {
118 ALC269_BASIC,
119 ALC269_AUTO,
120 ALC269_MODEL_LAST /* last tag */
121};
122
Kailang Yangdf694da2005-12-05 19:42:22 +0100123/* ALC861 models */
124enum {
125 ALC861_3ST,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200126 ALC660_3ST,
Kailang Yangdf694da2005-12-05 19:42:22 +0100127 ALC861_3ST_DIG,
128 ALC861_6ST_DIG,
Takashi Iwai22309c32006-08-09 16:57:28 +0200129 ALC861_UNIWILL_M31,
Tobin Davisa53d1ae2006-10-17 12:00:28 +0200130 ALC861_TOSHIBA,
Mariusz Domanski7cdbff92006-10-23 13:42:56 +0200131 ALC861_ASUS,
Takashi Iwai56bb0ca2006-11-22 11:52:52 +0100132 ALC861_ASUS_LAPTOP,
Kailang Yangdf694da2005-12-05 19:42:22 +0100133 ALC861_AUTO,
134 ALC861_MODEL_LAST,
135};
136
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100137/* ALC861-VD models */
138enum {
139 ALC660VD_3ST,
Mike Crash6963f842007-06-25 12:12:51 +0200140 ALC660VD_3ST_DIG,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100141 ALC861VD_3ST,
142 ALC861VD_3ST_DIG,
143 ALC861VD_6ST_DIG,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200144 ALC861VD_LENOVO,
Kailang Yang272a5272007-05-14 11:00:38 +0200145 ALC861VD_DALLAS,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200146 ALC861VD_HP,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100147 ALC861VD_AUTO,
148 ALC861VD_MODEL_LAST,
149};
150
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200151/* ALC662 models */
152enum {
153 ALC662_3ST_2ch_DIG,
154 ALC662_3ST_6ch_DIG,
155 ALC662_3ST_6ch,
156 ALC662_5ST_DIG,
157 ALC662_LENOVO_101E,
Kailang Yang291702f2007-10-16 14:28:03 +0200158 ALC662_ASUS_EEEPC_P701,
Kailang Yang8c427222008-01-10 13:03:59 +0100159 ALC662_ASUS_EEEPC_EP20,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200160 ALC662_AUTO,
161 ALC662_MODEL_LAST,
162};
163
Kailang Yangdf694da2005-12-05 19:42:22 +0100164/* ALC882 models */
165enum {
166 ALC882_3ST_DIG,
167 ALC882_6ST_DIG,
Takashi Iwai4b146cb2006-07-28 14:42:36 +0200168 ALC882_ARIMA,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200169 ALC882_W2JC,
Kailang Yang272a5272007-05-14 11:00:38 +0200170 ALC882_TARGA,
171 ALC882_ASUS_A7J,
Takashi Iwai914759b2007-09-06 14:52:04 +0200172 ALC882_ASUS_A7M,
Tobin Davis9102cd12006-12-15 10:02:12 +0100173 ALC885_MACPRO,
Takashi Iwai87350ad2007-08-16 18:19:38 +0200174 ALC885_MBP3,
Nicola Fagnanic54728d2007-07-19 23:28:52 +0200175 ALC885_IMAC24,
Kailang Yang272a5272007-05-14 11:00:38 +0200176 ALC882_AUTO,
Kailang Yangdf694da2005-12-05 19:42:22 +0100177 ALC882_MODEL_LAST,
178};
179
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200180/* ALC883 models */
181enum {
182 ALC883_3ST_2ch_DIG,
183 ALC883_3ST_6ch_DIG,
184 ALC883_3ST_6ch,
185 ALC883_6ST_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +0200186 ALC883_TARGA_DIG,
187 ALC883_TARGA_2ch_DIG,
Vladimir Avdoninbab282b92006-08-22 13:31:58 +0200188 ALC883_ACER,
Tobin Davis2880a862007-08-07 11:50:26 +0200189 ALC883_ACER_ASPIRE,
Tobin Davisc07584c2006-10-13 12:32:16 +0200190 ALC883_MEDION,
Kailang Yang272a5272007-05-14 11:00:38 +0200191 ALC883_MEDION_MD2,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +0100192 ALC883_LAPTOP_EAPD,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200193 ALC883_LENOVO_101E_2ch,
Kailang Yang272a5272007-05-14 11:00:38 +0200194 ALC883_LENOVO_NB0763,
Kailang Yang189609a2007-08-20 11:31:23 +0200195 ALC888_LENOVO_MS7195_DIG,
196 ALC883_HAIER_W66,
Claudio Matsuoka4723c022007-07-13 14:36:19 +0200197 ALC888_6ST_HP,
198 ALC888_3ST_HP,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +0100199 ALC888_6ST_DELL,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +0100200 ALC883_MITAC,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200201 ALC883_AUTO,
202 ALC883_MODEL_LAST,
203};
204
Kailang Yangdf694da2005-12-05 19:42:22 +0100205/* for GPIO Poll */
206#define GPIO_MASK 0x03
207
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208struct alc_spec {
209 /* codec parameterization */
Kailang Yangdf694da2005-12-05 19:42:22 +0100210 struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 unsigned int num_mixers;
212
Kailang Yangdf694da2005-12-05 19:42:22 +0100213 const struct hda_verb *init_verbs[5]; /* initialization verbs
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200214 * don't forget NULL
215 * termination!
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200216 */
217 unsigned int num_init_verbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218
Takashi Iwai16ded522005-06-10 19:58:24 +0200219 char *stream_name_analog; /* analog PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 struct hda_pcm_stream *stream_analog_playback;
221 struct hda_pcm_stream *stream_analog_capture;
222
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200223 char *stream_name_digital; /* digital PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 struct hda_pcm_stream *stream_digital_playback;
225 struct hda_pcm_stream *stream_digital_capture;
226
227 /* playback */
Takashi Iwai16ded522005-06-10 19:58:24 +0200228 struct hda_multi_out multiout; /* playback set-up
229 * max_channels, dacs must be set
230 * dig_out_nid and hp_nid are optional
231 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232
233 /* capture */
234 unsigned int num_adc_nids;
235 hda_nid_t *adc_nids;
Takashi Iwai16ded522005-06-10 19:58:24 +0200236 hda_nid_t dig_in_nid; /* digital-in NID; optional */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237
238 /* capture source */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200239 unsigned int num_mux_defs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 const struct hda_input_mux *input_mux;
241 unsigned int cur_mux[3];
242
243 /* channel model */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100244 const struct hda_channel_mode *channel_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 int num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200246 int need_dac_fix;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247
248 /* PCM information */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100249 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
Takashi Iwai41e41f12005-06-08 14:48:49 +0200250
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200251 /* dynamic controls, init_verbs and input_mux */
252 struct auto_pin_cfg autocfg;
253 unsigned int num_kctl_alloc, num_kctl_used;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100254 struct snd_kcontrol_new *kctl_alloc;
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200255 struct hda_input_mux private_imux;
Takashi Iwai41923e42007-10-22 17:20:10 +0200256 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai834be882006-03-01 14:16:17 +0100257
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100258 /* hooks */
259 void (*init_hook)(struct hda_codec *codec);
260 void (*unsol_event)(struct hda_codec *codec, unsigned int res);
261
Takashi Iwai834be882006-03-01 14:16:17 +0100262 /* for pin sensing */
263 unsigned int sense_updated: 1;
264 unsigned int jack_present: 1;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200265
Takashi Iwai2134ea42008-01-10 16:53:55 +0100266 /* for virtual master */
267 hda_nid_t vmaster_nid;
268 u32 vmaster_tlv[4];
Takashi Iwaicb53c622007-08-10 17:21:45 +0200269#ifdef CONFIG_SND_HDA_POWER_SAVE
270 struct hda_loopback_check loopback;
271#endif
Kailang Yangdf694da2005-12-05 19:42:22 +0100272};
273
274/*
275 * configuration template - to be copied to the spec instance
276 */
277struct alc_config_preset {
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200278 struct snd_kcontrol_new *mixers[5]; /* should be identical size
279 * with spec
280 */
Kailang Yangdf694da2005-12-05 19:42:22 +0100281 const struct hda_verb *init_verbs[5];
282 unsigned int num_dacs;
283 hda_nid_t *dac_nids;
284 hda_nid_t dig_out_nid; /* optional */
285 hda_nid_t hp_nid; /* optional */
286 unsigned int num_adc_nids;
287 hda_nid_t *adc_nids;
288 hda_nid_t dig_in_nid;
289 unsigned int num_channel_mode;
290 const struct hda_channel_mode *channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200291 int need_dac_fix;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200292 unsigned int num_mux_defs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100293 const struct hda_input_mux *input_mux;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100294 void (*unsol_event)(struct hda_codec *, unsigned int);
295 void (*init_hook)(struct hda_codec *);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200296#ifdef CONFIG_SND_HDA_POWER_SAVE
297 struct hda_amp_list *loopbacks;
298#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299};
300
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301
302/*
303 * input MUX handling
304 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200305static int alc_mux_enum_info(struct snd_kcontrol *kcontrol,
306 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307{
308 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
309 struct alc_spec *spec = codec->spec;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200310 unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id);
311 if (mux_idx >= spec->num_mux_defs)
312 mux_idx = 0;
313 return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314}
315
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200316static int alc_mux_enum_get(struct snd_kcontrol *kcontrol,
317 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318{
319 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
320 struct alc_spec *spec = codec->spec;
321 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
322
323 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
324 return 0;
325}
326
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200327static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
328 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329{
330 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
331 struct alc_spec *spec = codec->spec;
332 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200333 unsigned int mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
334 return snd_hda_input_mux_put(codec, &spec->input_mux[mux_idx], ucontrol,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200335 spec->adc_nids[adc_idx],
336 &spec->cur_mux[adc_idx]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337}
338
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200339
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340/*
341 * channel mode setting
342 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200343static int alc_ch_mode_info(struct snd_kcontrol *kcontrol,
344 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345{
346 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
347 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100348 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
349 spec->num_channel_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350}
351
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200352static int alc_ch_mode_get(struct snd_kcontrol *kcontrol,
353 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354{
355 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
356 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100357 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200358 spec->num_channel_mode,
359 spec->multiout.max_channels);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360}
361
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200362static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
363 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364{
365 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
366 struct alc_spec *spec = codec->spec;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200367 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
368 spec->num_channel_mode,
369 &spec->multiout.max_channels);
Takashi Iwaibd2033f2006-10-10 19:49:31 +0200370 if (err >= 0 && spec->need_dac_fix)
Takashi Iwai4e195a72006-07-28 14:47:34 +0200371 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
372 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373}
374
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375/*
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100376 * Control the mode of pin widget settings via the mixer. "pc" is used
377 * instead of "%" to avoid consequences of accidently treating the % as
378 * being part of a format specifier. Maximum allowed length of a value is
379 * 63 characters plus NULL terminator.
Jonathan Woithe7cf51e482006-02-09 12:01:26 +0100380 *
381 * Note: some retasking pin complexes seem to ignore requests for input
382 * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these
383 * are requested. Therefore order this list so that this behaviour will not
384 * cause problems when mixer clients move through the enum sequentially.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200385 * NIDs 0x0f and 0x10 have been observed to have this behaviour as of
386 * March 2006.
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200387 */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100388static char *alc_pin_mode_names[] = {
Jonathan Woithe7cf51e482006-02-09 12:01:26 +0100389 "Mic 50pc bias", "Mic 80pc bias",
390 "Line in", "Line out", "Headphone out",
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100391};
392static unsigned char alc_pin_mode_values[] = {
Jonathan Woithe7cf51e482006-02-09 12:01:26 +0100393 PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100394};
395/* The control can present all 5 options, or it can limit the options based
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200396 * in the pin being assumed to be exclusively an input or an output pin. In
397 * addition, "input" pins may or may not process the mic bias option
398 * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to
399 * accept requests for bias as of chip versions up to March 2006) and/or
400 * wiring in the computer.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100401 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200402#define ALC_PIN_DIR_IN 0x00
403#define ALC_PIN_DIR_OUT 0x01
404#define ALC_PIN_DIR_INOUT 0x02
405#define ALC_PIN_DIR_IN_NOMICBIAS 0x03
406#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100407
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200408/* Info about the pin modes supported by the different pin direction modes.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100409 * For each direction the minimum and maximum values are given.
410 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200411static signed char alc_pin_mode_dir_info[5][2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100412 { 0, 2 }, /* ALC_PIN_DIR_IN */
413 { 3, 4 }, /* ALC_PIN_DIR_OUT */
414 { 0, 4 }, /* ALC_PIN_DIR_INOUT */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200415 { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */
416 { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100417};
418#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0])
419#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1])
420#define alc_pin_mode_n_items(_dir) \
421 (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1)
422
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200423static int alc_pin_mode_info(struct snd_kcontrol *kcontrol,
424 struct snd_ctl_elem_info *uinfo)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200425{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100426 unsigned int item_num = uinfo->value.enumerated.item;
427 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
428
429 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200430 uinfo->count = 1;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100431 uinfo->value.enumerated.items = alc_pin_mode_n_items(dir);
432
433 if (item_num<alc_pin_mode_min(dir) || item_num>alc_pin_mode_max(dir))
434 item_num = alc_pin_mode_min(dir);
435 strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200436 return 0;
437}
438
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200439static int alc_pin_mode_get(struct snd_kcontrol *kcontrol,
440 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200441{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100442 unsigned int i;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200443 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
444 hda_nid_t nid = kcontrol->private_value & 0xffff;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100445 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200446 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200447 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
448 AC_VERB_GET_PIN_WIDGET_CONTROL,
449 0x00);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200450
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100451 /* Find enumerated value for current pinctl setting */
452 i = alc_pin_mode_min(dir);
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200453 while (alc_pin_mode_values[i] != pinctl && i <= alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100454 i++;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200455 *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100456 return 0;
457}
458
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200459static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
460 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100461{
462 signed int change;
463 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
464 hda_nid_t nid = kcontrol->private_value & 0xffff;
465 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
466 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200467 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
468 AC_VERB_GET_PIN_WIDGET_CONTROL,
469 0x00);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100470
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200471 if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100472 val = alc_pin_mode_min(dir);
473
474 change = pinctl != alc_pin_mode_values[val];
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100475 if (change) {
476 /* Set pin mode to that requested */
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200477 snd_hda_codec_write_cache(codec, nid, 0,
478 AC_VERB_SET_PIN_WIDGET_CONTROL,
479 alc_pin_mode_values[val]);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100480
481 /* Also enable the retasking pin's input/output as required
482 * for the requested pin mode. Enum values of 2 or less are
483 * input modes.
484 *
485 * Dynamically switching the input/output buffers probably
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200486 * reduces noise slightly (particularly on input) so we'll
487 * do it. However, having both input and output buffers
488 * enabled simultaneously doesn't seem to be problematic if
489 * this turns out to be necessary in the future.
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100490 */
491 if (val <= 2) {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200492 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
493 HDA_AMP_MUTE, HDA_AMP_MUTE);
494 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
495 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100496 } else {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200497 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
498 HDA_AMP_MUTE, HDA_AMP_MUTE);
499 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
500 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100501 }
502 }
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200503 return change;
504}
505
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100506#define ALC_PIN_MODE(xname, nid, dir) \
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200507 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100508 .info = alc_pin_mode_info, \
509 .get = alc_pin_mode_get, \
510 .put = alc_pin_mode_put, \
511 .private_value = nid | (dir<<16) }
Kailang Yangdf694da2005-12-05 19:42:22 +0100512
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100513/* A switch control for ALC260 GPIO pins. Multiple GPIOs can be ganged
514 * together using a mask with more than one bit set. This control is
515 * currently used only by the ALC260 test model. At this stage they are not
516 * needed for any "production" models.
517 */
518#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200519#define alc_gpio_data_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200520
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200521static int alc_gpio_data_get(struct snd_kcontrol *kcontrol,
522 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100523{
524 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
525 hda_nid_t nid = kcontrol->private_value & 0xffff;
526 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
527 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200528 unsigned int val = snd_hda_codec_read(codec, nid, 0,
529 AC_VERB_GET_GPIO_DATA, 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100530
531 *valp = (val & mask) != 0;
532 return 0;
533}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200534static int alc_gpio_data_put(struct snd_kcontrol *kcontrol,
535 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100536{
537 signed int change;
538 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
539 hda_nid_t nid = kcontrol->private_value & 0xffff;
540 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
541 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200542 unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0,
543 AC_VERB_GET_GPIO_DATA,
544 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100545
546 /* Set/unset the masked GPIO bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200547 change = (val == 0 ? 0 : mask) != (gpio_data & mask);
548 if (val == 0)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100549 gpio_data &= ~mask;
550 else
551 gpio_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200552 snd_hda_codec_write_cache(codec, nid, 0,
553 AC_VERB_SET_GPIO_DATA, gpio_data);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100554
555 return change;
556}
557#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
558 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
559 .info = alc_gpio_data_info, \
560 .get = alc_gpio_data_get, \
561 .put = alc_gpio_data_put, \
562 .private_value = nid | (mask<<16) }
563#endif /* CONFIG_SND_DEBUG */
564
Jonathan Woithe92621f12006-02-28 11:47:47 +0100565/* A switch control to allow the enabling of the digital IO pins on the
566 * ALC260. This is incredibly simplistic; the intention of this control is
567 * to provide something in the test model allowing digital outputs to be
568 * identified if present. If models are found which can utilise these
569 * outputs a more complete mixer control can be devised for those models if
570 * necessary.
571 */
572#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200573#define alc_spdif_ctrl_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200574
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200575static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol,
576 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100577{
578 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
579 hda_nid_t nid = kcontrol->private_value & 0xffff;
580 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
581 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200582 unsigned int val = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100583 AC_VERB_GET_DIGI_CONVERT_1, 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100584
585 *valp = (val & mask) != 0;
586 return 0;
587}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200588static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
589 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100590{
591 signed int change;
592 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
593 hda_nid_t nid = kcontrol->private_value & 0xffff;
594 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
595 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200596 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100597 AC_VERB_GET_DIGI_CONVERT_1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200598 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100599
600 /* Set/unset the masked control bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200601 change = (val == 0 ? 0 : mask) != (ctrl_data & mask);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100602 if (val==0)
603 ctrl_data &= ~mask;
604 else
605 ctrl_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200606 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
607 ctrl_data);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100608
609 return change;
610}
611#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \
612 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
613 .info = alc_spdif_ctrl_info, \
614 .get = alc_spdif_ctrl_get, \
615 .put = alc_spdif_ctrl_put, \
616 .private_value = nid | (mask<<16) }
617#endif /* CONFIG_SND_DEBUG */
618
Jonathan Woithef8225f62008-01-08 12:16:54 +0100619/* A switch control to allow the enabling EAPD digital outputs on the ALC26x.
620 * Again, this is only used in the ALC26x test models to help identify when
621 * the EAPD line must be asserted for features to work.
622 */
623#ifdef CONFIG_SND_DEBUG
624#define alc_eapd_ctrl_info snd_ctl_boolean_mono_info
625
626static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol,
627 struct snd_ctl_elem_value *ucontrol)
628{
629 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
630 hda_nid_t nid = kcontrol->private_value & 0xffff;
631 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
632 long *valp = ucontrol->value.integer.value;
633 unsigned int val = snd_hda_codec_read(codec, nid, 0,
634 AC_VERB_GET_EAPD_BTLENABLE, 0x00);
635
636 *valp = (val & mask) != 0;
637 return 0;
638}
639
640static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
641 struct snd_ctl_elem_value *ucontrol)
642{
643 int change;
644 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
645 hda_nid_t nid = kcontrol->private_value & 0xffff;
646 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
647 long val = *ucontrol->value.integer.value;
648 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
649 AC_VERB_GET_EAPD_BTLENABLE,
650 0x00);
651
652 /* Set/unset the masked control bit(s) as needed */
653 change = (!val ? 0 : mask) != (ctrl_data & mask);
654 if (!val)
655 ctrl_data &= ~mask;
656 else
657 ctrl_data |= mask;
658 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
659 ctrl_data);
660
661 return change;
662}
663
664#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \
665 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
666 .info = alc_eapd_ctrl_info, \
667 .get = alc_eapd_ctrl_get, \
668 .put = alc_eapd_ctrl_put, \
669 .private_value = nid | (mask<<16) }
670#endif /* CONFIG_SND_DEBUG */
671
Kailang Yangdf694da2005-12-05 19:42:22 +0100672/*
673 * set up from the preset table
674 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200675static void setup_preset(struct alc_spec *spec,
676 const struct alc_config_preset *preset)
Kailang Yangdf694da2005-12-05 19:42:22 +0100677{
678 int i;
679
680 for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
681 spec->mixers[spec->num_mixers++] = preset->mixers[i];
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200682 for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i];
683 i++)
684 spec->init_verbs[spec->num_init_verbs++] =
685 preset->init_verbs[i];
Kailang Yangdf694da2005-12-05 19:42:22 +0100686
687 spec->channel_mode = preset->channel_mode;
688 spec->num_channel_mode = preset->num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200689 spec->need_dac_fix = preset->need_dac_fix;
Kailang Yangdf694da2005-12-05 19:42:22 +0100690
691 spec->multiout.max_channels = spec->channel_mode[0].channels;
692
693 spec->multiout.num_dacs = preset->num_dacs;
694 spec->multiout.dac_nids = preset->dac_nids;
695 spec->multiout.dig_out_nid = preset->dig_out_nid;
696 spec->multiout.hp_nid = preset->hp_nid;
697
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200698 spec->num_mux_defs = preset->num_mux_defs;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200699 if (!spec->num_mux_defs)
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200700 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +0100701 spec->input_mux = preset->input_mux;
702
703 spec->num_adc_nids = preset->num_adc_nids;
704 spec->adc_nids = preset->adc_nids;
705 spec->dig_in_nid = preset->dig_in_nid;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100706
707 spec->unsol_event = preset->unsol_event;
708 spec->init_hook = preset->init_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200709#ifdef CONFIG_SND_HDA_POWER_SAVE
710 spec->loopback.amplist = preset->loopbacks;
711#endif
Kailang Yangdf694da2005-12-05 19:42:22 +0100712}
713
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200714/* Enable GPIO mask and set output */
715static struct hda_verb alc_gpio1_init_verbs[] = {
716 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
717 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
718 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
719 { }
720};
721
722static struct hda_verb alc_gpio2_init_verbs[] = {
723 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
724 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
725 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
726 { }
727};
728
Kailang Yangbdd148a2007-05-08 15:19:08 +0200729static struct hda_verb alc_gpio3_init_verbs[] = {
730 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
731 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
732 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
733 { }
734};
735
Kailang Yangc9b58002007-10-16 14:30:01 +0200736static void alc_sku_automute(struct hda_codec *codec)
737{
738 struct alc_spec *spec = codec->spec;
739 unsigned int mute;
740 unsigned int present;
741 unsigned int hp_nid = spec->autocfg.hp_pins[0];
742 unsigned int sp_nid = spec->autocfg.speaker_pins[0];
743
744 /* need to execute and sync at first */
745 snd_hda_codec_read(codec, hp_nid, 0, AC_VERB_SET_PIN_SENSE, 0);
746 present = snd_hda_codec_read(codec, hp_nid, 0,
747 AC_VERB_GET_PIN_SENSE, 0);
748 spec->jack_present = (present & 0x80000000) != 0;
749 if (spec->jack_present) {
750 /* mute internal speaker */
751 snd_hda_codec_amp_stereo(codec, sp_nid, HDA_OUTPUT, 0,
752 HDA_AMP_MUTE, HDA_AMP_MUTE);
753 } else {
754 /* unmute internal speaker if necessary */
755 mute = snd_hda_codec_amp_read(codec, hp_nid, 0, HDA_OUTPUT, 0);
756 snd_hda_codec_amp_stereo(codec, sp_nid, HDA_OUTPUT, 0,
757 HDA_AMP_MUTE, mute);
758 }
759}
760
761/* unsolicited event for HP jack sensing */
762static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
763{
764 if (codec->vendor_id == 0x10ec0880)
765 res >>= 28;
766 else
767 res >>= 26;
768 if (res != ALC880_HP_EVENT)
769 return;
770
771 alc_sku_automute(codec);
772}
773
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200774/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
775 * 31 ~ 16 : Manufacture ID
776 * 15 ~ 8 : SKU ID
777 * 7 ~ 0 : Assembly ID
778 * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
779 */
780static void alc_subsystem_id(struct hda_codec *codec,
781 unsigned int porta, unsigned int porte,
782 unsigned int portd)
783{
Kailang Yangc9b58002007-10-16 14:30:01 +0200784 unsigned int ass, tmp, i;
785 unsigned nid;
786 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200787
Kailang Yangc9b58002007-10-16 14:30:01 +0200788 ass = codec->subsystem_id & 0xffff;
789 if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
790 goto do_sku;
791
792 /*
793 * 31~30 : port conetcivity
794 * 29~21 : reserve
795 * 20 : PCBEEP input
796 * 19~16 : Check sum (15:1)
797 * 15~1 : Custom
798 * 0 : override
799 */
800 nid = 0x1d;
801 if (codec->vendor_id == 0x10ec0260)
802 nid = 0x17;
803 ass = snd_hda_codec_read(codec, nid, 0,
804 AC_VERB_GET_CONFIG_DEFAULT, 0);
805 if (!(ass & 1) && !(ass & 0x100000))
806 return;
807 if ((ass >> 30) != 1) /* no physical connection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200808 return;
809
Kailang Yangc9b58002007-10-16 14:30:01 +0200810 /* check sum */
811 tmp = 0;
812 for (i = 1; i < 16; i++) {
Kailang Yang8c427222008-01-10 13:03:59 +0100813 if ((ass >> i) & 1)
Kailang Yangc9b58002007-10-16 14:30:01 +0200814 tmp++;
815 }
816 if (((ass >> 16) & 0xf) != tmp)
817 return;
818do_sku:
819 /*
820 * 0 : override
821 * 1 : Swap Jack
822 * 2 : 0 --> Desktop, 1 --> Laptop
823 * 3~5 : External Amplifier control
824 * 7~6 : Reserved
825 */
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200826 tmp = (ass & 0x38) >> 3; /* external Amp control */
827 switch (tmp) {
828 case 1:
829 snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
830 break;
831 case 3:
832 snd_hda_sequence_write(codec, alc_gpio2_init_verbs);
833 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +0200834 case 7:
835 snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
836 break;
Kailang Yangc9b58002007-10-16 14:30:01 +0200837 case 5: /* set EAPD output high */
Kailang Yangbdd148a2007-05-08 15:19:08 +0200838 switch (codec->vendor_id) {
Kailang Yangc9b58002007-10-16 14:30:01 +0200839 case 0x10ec0260:
840 snd_hda_codec_write(codec, 0x0f, 0,
841 AC_VERB_SET_EAPD_BTLENABLE, 2);
842 snd_hda_codec_write(codec, 0x10, 0,
843 AC_VERB_SET_EAPD_BTLENABLE, 2);
844 break;
845 case 0x10ec0262:
Kailang Yangbdd148a2007-05-08 15:19:08 +0200846 case 0x10ec0267:
847 case 0x10ec0268:
Kailang Yangc9b58002007-10-16 14:30:01 +0200848 case 0x10ec0269:
849 case 0x10ec0862:
850 case 0x10ec0662:
Kailang Yangbdd148a2007-05-08 15:19:08 +0200851 snd_hda_codec_write(codec, 0x14, 0,
852 AC_VERB_SET_EAPD_BTLENABLE, 2);
853 snd_hda_codec_write(codec, 0x15, 0,
854 AC_VERB_SET_EAPD_BTLENABLE, 2);
Kailang Yangc9b58002007-10-16 14:30:01 +0200855 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +0200856 }
Kailang Yangc9b58002007-10-16 14:30:01 +0200857 switch (codec->vendor_id) {
858 case 0x10ec0260:
859 snd_hda_codec_write(codec, 0x1a, 0,
860 AC_VERB_SET_COEF_INDEX, 7);
861 tmp = snd_hda_codec_read(codec, 0x1a, 0,
862 AC_VERB_GET_PROC_COEF, 0);
863 snd_hda_codec_write(codec, 0x1a, 0,
864 AC_VERB_SET_COEF_INDEX, 7);
865 snd_hda_codec_write(codec, 0x1a, 0,
866 AC_VERB_SET_PROC_COEF,
867 tmp | 0x2010);
868 break;
869 case 0x10ec0262:
870 case 0x10ec0880:
871 case 0x10ec0882:
872 case 0x10ec0883:
873 case 0x10ec0885:
874 case 0x10ec0888:
875 snd_hda_codec_write(codec, 0x20, 0,
876 AC_VERB_SET_COEF_INDEX, 7);
877 tmp = snd_hda_codec_read(codec, 0x20, 0,
878 AC_VERB_GET_PROC_COEF, 0);
879 snd_hda_codec_write(codec, 0x20, 0,
880 AC_VERB_SET_COEF_INDEX, 7);
881 snd_hda_codec_write(codec, 0x20, 0,
882 AC_VERB_SET_PROC_COEF,
883 tmp | 0x2010);
884 break;
885 case 0x10ec0267:
886 case 0x10ec0268:
887 snd_hda_codec_write(codec, 0x20, 0,
888 AC_VERB_SET_COEF_INDEX, 7);
889 tmp = snd_hda_codec_read(codec, 0x20, 0,
890 AC_VERB_GET_PROC_COEF, 0);
891 snd_hda_codec_write(codec, 0x20, 0,
892 AC_VERB_SET_COEF_INDEX, 7);
893 snd_hda_codec_write(codec, 0x20, 0,
894 AC_VERB_SET_PROC_COEF,
895 tmp | 0x3000);
896 break;
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200897 }
Kailang Yangc9b58002007-10-16 14:30:01 +0200898 default:
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200899 break;
900 }
Kailang Yangc9b58002007-10-16 14:30:01 +0200901
Kailang Yang8c427222008-01-10 13:03:59 +0100902 /* is laptop or Desktop and enable the function "Mute internal speaker
Kailang Yangc9b58002007-10-16 14:30:01 +0200903 * when the external headphone out jack is plugged"
904 */
Kailang Yang8c427222008-01-10 13:03:59 +0100905 if (!(ass & 0x8000))
Kailang Yangc9b58002007-10-16 14:30:01 +0200906 return;
907 /*
908 * 10~8 : Jack location
909 * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
910 * 14~13: Resvered
911 * 15 : 1 --> enable the function "Mute internal speaker
912 * when the external headphone out jack is plugged"
913 */
914 if (!spec->autocfg.speaker_pins[0]) {
Kailang Yang8c427222008-01-10 13:03:59 +0100915 if (spec->autocfg.line_out_pins[0])
Kailang Yangc9b58002007-10-16 14:30:01 +0200916 spec->autocfg.speaker_pins[0] =
Kailang Yang8c427222008-01-10 13:03:59 +0100917 spec->autocfg.line_out_pins[0];
Kailang Yangc9b58002007-10-16 14:30:01 +0200918 else
919 return;
920 }
921
922 if (!spec->autocfg.hp_pins[0]) {
923 tmp = (ass >> 11) & 0x3; /* HP to chassis */
924 if (tmp == 0)
925 spec->autocfg.hp_pins[0] = porta;
926 else if (tmp == 1)
927 spec->autocfg.hp_pins[0] = porte;
928 else if (tmp == 2)
929 spec->autocfg.hp_pins[0] = portd;
930 else
931 return;
932 }
933
934 snd_hda_codec_write(codec, spec->autocfg.hp_pins[0], 0,
935 AC_VERB_SET_UNSOLICITED_ENABLE,
936 AC_USRSP_EN | ALC880_HP_EVENT);
937 spec->unsol_event = alc_sku_unsol_event;
938 spec->init_hook = alc_sku_automute;
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200939}
940
Takashi Iwai41e41f12005-06-08 14:48:49 +0200941/*
Takashi Iwaif95474e2007-07-10 00:47:43 +0200942 * Fix-up pin default configurations
943 */
944
945struct alc_pincfg {
946 hda_nid_t nid;
947 u32 val;
948};
949
950static void alc_fix_pincfg(struct hda_codec *codec,
951 const struct snd_pci_quirk *quirk,
952 const struct alc_pincfg **pinfix)
953{
954 const struct alc_pincfg *cfg;
955
956 quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
957 if (!quirk)
958 return;
959
960 cfg = pinfix[quirk->value];
961 for (; cfg->nid; cfg++) {
962 int i;
963 u32 val = cfg->val;
964 for (i = 0; i < 4; i++) {
965 snd_hda_codec_write(codec, cfg->nid, 0,
966 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 + i,
967 val & 0xff);
968 val >>= 8;
969 }
970 }
971}
972
973/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200974 * ALC880 3-stack model
975 *
976 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200977 * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18,
978 * F-Mic = 0x1b, HP = 0x19
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 */
980
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200981static hda_nid_t alc880_dac_nids[4] = {
982 /* front, rear, clfe, rear_surr */
983 0x02, 0x05, 0x04, 0x03
984};
985
986static hda_nid_t alc880_adc_nids[3] = {
987 /* ADC0-2 */
988 0x07, 0x08, 0x09,
989};
990
991/* The datasheet says the node 0x07 is connected from inputs,
992 * but it shows zero connection in the real implementation on some devices.
Kailang Yangdf694da2005-12-05 19:42:22 +0100993 * Note: this is a 915GAV bug, fixed on 915GLV
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200995static hda_nid_t alc880_adc_nids_alt[2] = {
996 /* ADC1-2 */
997 0x08, 0x09,
998};
999
1000#define ALC880_DIGOUT_NID 0x06
1001#define ALC880_DIGIN_NID 0x0a
1002
1003static struct hda_input_mux alc880_capture_source = {
1004 .num_items = 4,
1005 .items = {
1006 { "Mic", 0x0 },
1007 { "Front Mic", 0x3 },
1008 { "Line", 0x2 },
1009 { "CD", 0x4 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001011};
1012
1013/* channel source setting (2/6 channel selection for 3-stack) */
1014/* 2ch mode */
1015static struct hda_verb alc880_threestack_ch2_init[] = {
1016 /* set line-in to input, mute it */
1017 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1018 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1019 /* set mic-in to input vref 80%, mute it */
1020 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1021 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 { } /* end */
1023};
1024
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001025/* 6ch mode */
1026static struct hda_verb alc880_threestack_ch6_init[] = {
1027 /* set line-in to output, unmute it */
1028 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1029 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1030 /* set mic-in to output, unmute it */
1031 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1032 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1033 { } /* end */
1034};
1035
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001036static struct hda_channel_mode alc880_threestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001037 { 2, alc880_threestack_ch2_init },
1038 { 6, alc880_threestack_ch6_init },
1039};
1040
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001041static struct snd_kcontrol_new alc880_three_stack_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02001042 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001043 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02001044 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001045 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02001046 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1047 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001048 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1049 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1051 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1052 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1053 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1054 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1055 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1056 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
1057 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
1058 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1059 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001061 {
1062 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1063 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001064 .info = alc_ch_mode_info,
1065 .get = alc_ch_mode_get,
1066 .put = alc_ch_mode_put,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001067 },
1068 { } /* end */
1069};
1070
1071/* capture mixer elements */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001072static struct snd_kcontrol_new alc880_capture_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001073 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
1074 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
1075 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
1076 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
1077 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
1078 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
1079 {
1080 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1081 /* The multiple "Capture Source" controls confuse alsamixer
1082 * So call somewhat different..
1083 * FIXME: the controls appear in the "playback" view!
1084 */
1085 /* .name = "Capture Source", */
1086 .name = "Input Source",
1087 .count = 3,
1088 .info = alc_mux_enum_info,
1089 .get = alc_mux_enum_get,
1090 .put = alc_mux_enum_put,
1091 },
1092 { } /* end */
1093};
1094
1095/* capture mixer elements (in case NID 0x07 not available) */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001096static struct snd_kcontrol_new alc880_capture_alt_mixer[] = {
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001097 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
1098 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
1099 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
1100 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 {
1102 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1103 /* The multiple "Capture Source" controls confuse alsamixer
1104 * So call somewhat different..
1105 * FIXME: the controls appear in the "playback" view!
1106 */
1107 /* .name = "Capture Source", */
1108 .name = "Input Source",
1109 .count = 2,
1110 .info = alc_mux_enum_info,
1111 .get = alc_mux_enum_get,
1112 .put = alc_mux_enum_put,
1113 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 { } /* end */
1115};
1116
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001117
1118
1119/*
1120 * ALC880 5-stack model
1121 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001122 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d),
1123 * Side = 0x02 (0xd)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001124 * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
1125 * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
1126 */
1127
1128/* additional mixers to alc880_three_stack_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001129static struct snd_kcontrol_new alc880_five_stack_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001130 HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001131 HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 { } /* end */
1133};
1134
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001135/* channel source setting (6/8 channel selection for 5-stack) */
1136/* 6ch mode */
1137static struct hda_verb alc880_fivestack_ch6_init[] = {
1138 /* set line-in to input, mute it */
1139 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1140 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001141 { } /* end */
1142};
1143
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001144/* 8ch mode */
1145static struct hda_verb alc880_fivestack_ch8_init[] = {
1146 /* set line-in to output, unmute it */
1147 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1148 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1149 { } /* end */
1150};
1151
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001152static struct hda_channel_mode alc880_fivestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001153 { 6, alc880_fivestack_ch6_init },
1154 { 8, alc880_fivestack_ch8_init },
1155};
1156
1157
1158/*
1159 * ALC880 6-stack model
1160 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001161 * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e),
1162 * Side = 0x05 (0x0f)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001163 * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
1164 * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
1165 */
1166
1167static hda_nid_t alc880_6st_dac_nids[4] = {
1168 /* front, rear, clfe, rear_surr */
1169 0x02, 0x03, 0x04, 0x05
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001170};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001171
1172static struct hda_input_mux alc880_6stack_capture_source = {
1173 .num_items = 4,
1174 .items = {
1175 { "Mic", 0x0 },
1176 { "Front Mic", 0x1 },
1177 { "Line", 0x2 },
1178 { "CD", 0x4 },
1179 },
1180};
1181
1182/* fixed 8-channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001183static struct hda_channel_mode alc880_sixstack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001184 { 8, NULL },
1185};
1186
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001187static struct snd_kcontrol_new alc880_six_stack_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001188 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001189 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001190 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001191 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001192 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1193 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001194 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1195 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001196 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001197 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001198 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1199 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1200 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1201 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1202 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1203 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1204 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1205 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1206 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1207 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001208 {
1209 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1210 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001211 .info = alc_ch_mode_info,
1212 .get = alc_ch_mode_get,
1213 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02001214 },
1215 { } /* end */
1216};
1217
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001218
1219/*
1220 * ALC880 W810 model
1221 *
1222 * W810 has rear IO for:
1223 * Front (DAC 02)
1224 * Surround (DAC 03)
1225 * Center/LFE (DAC 04)
1226 * Digital out (06)
1227 *
1228 * The system also has a pair of internal speakers, and a headphone jack.
1229 * These are both connected to Line2 on the codec, hence to DAC 02.
1230 *
1231 * There is a variable resistor to control the speaker or headphone
1232 * volume. This is a hardware-only device without a software API.
1233 *
1234 * Plugging headphones in will disable the internal speakers. This is
1235 * implemented in hardware, not via the driver using jack sense. In
1236 * a similar fashion, plugging into the rear socket marked "front" will
1237 * disable both the speakers and headphones.
1238 *
1239 * For input, there's a microphone jack, and an "audio in" jack.
1240 * These may not do anything useful with this driver yet, because I
1241 * haven't setup any initialization verbs for these yet...
1242 */
1243
1244static hda_nid_t alc880_w810_dac_nids[3] = {
1245 /* front, rear/surround, clfe */
1246 0x02, 0x03, 0x04
1247};
1248
1249/* fixed 6 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001250static struct hda_channel_mode alc880_w810_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001251 { 6, NULL }
1252};
1253
1254/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001255static struct snd_kcontrol_new alc880_w810_base_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001256 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001257 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001258 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001259 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001260 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1261 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001262 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1263 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001264 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1265 { } /* end */
1266};
1267
1268
1269/*
1270 * Z710V model
1271 *
1272 * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001273 * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?),
1274 * Line = 0x1a
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001275 */
1276
1277static hda_nid_t alc880_z71v_dac_nids[1] = {
1278 0x02
1279};
1280#define ALC880_Z71V_HP_DAC 0x03
1281
1282/* fixed 2 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001283static struct hda_channel_mode alc880_2_jack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001284 { 2, NULL }
1285};
1286
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001287static struct snd_kcontrol_new alc880_z71v_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001288 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001289 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001290 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001291 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001292 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1293 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1294 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1295 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1296 { } /* end */
1297};
1298
1299
1300/* FIXME! */
1301/*
1302 * ALC880 F1734 model
1303 *
1304 * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
1305 * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
1306 */
1307
1308static hda_nid_t alc880_f1734_dac_nids[1] = {
1309 0x03
1310};
1311#define ALC880_F1734_HP_DAC 0x02
1312
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001313static struct snd_kcontrol_new alc880_f1734_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001314 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001315 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01001316 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1317 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001318 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1319 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1320 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1321 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001322 { } /* end */
1323};
1324
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001325
1326/* FIXME! */
1327/*
1328 * ALC880 ASUS model
1329 *
1330 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
1331 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
1332 * Mic = 0x18, Line = 0x1a
1333 */
1334
1335#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */
1336#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */
1337
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001338static struct snd_kcontrol_new alc880_asus_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001339 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001340 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001341 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001342 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001343 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1344 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001345 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1346 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001347 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1348 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1349 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1350 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1351 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1352 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001353 {
1354 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1355 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001356 .info = alc_ch_mode_info,
1357 .get = alc_ch_mode_get,
1358 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02001359 },
1360 { } /* end */
1361};
1362
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001363/* FIXME! */
1364/*
1365 * ALC880 ASUS W1V model
1366 *
1367 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
1368 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
1369 * Mic = 0x18, Line = 0x1a, Line2 = 0x1b
1370 */
1371
1372/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001373static struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001374 HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
1375 HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001376 { } /* end */
1377};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001378
Takashi Iwai3c10a9d2005-08-23 20:02:27 +02001379/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001380static struct snd_kcontrol_new alc880_pcbeep_mixer[] = {
Takashi Iwai3c10a9d2005-08-23 20:02:27 +02001381 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1382 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
1383 { } /* end */
1384};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001385
Kailang Yangdf694da2005-12-05 19:42:22 +01001386/* TCL S700 */
1387static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
1388 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1389 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1390 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
1391 HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT),
1392 HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT),
1393 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT),
1394 HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT),
1395 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
1396 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
1397 {
1398 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1399 /* The multiple "Capture Source" controls confuse alsamixer
1400 * So call somewhat different..
1401 * FIXME: the controls appear in the "playback" view!
1402 */
1403 /* .name = "Capture Source", */
1404 .name = "Input Source",
1405 .count = 1,
1406 .info = alc_mux_enum_info,
1407 .get = alc_mux_enum_get,
1408 .put = alc_mux_enum_put,
1409 },
1410 { } /* end */
1411};
1412
Kailang Yangccc656c2006-10-17 12:32:26 +02001413/* Uniwill */
1414static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01001415 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1416 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1417 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1418 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02001419 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1420 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
1421 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1422 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
1423 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1424 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1425 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1426 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1427 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1428 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1429 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1430 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1431 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1432 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
1433 {
1434 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1435 .name = "Channel Mode",
1436 .info = alc_ch_mode_info,
1437 .get = alc_ch_mode_get,
1438 .put = alc_ch_mode_put,
1439 },
1440 { } /* end */
1441};
1442
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01001443static struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
1444 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1445 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1446 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1447 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
1448 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1449 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1450 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1451 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1452 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1453 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1454 { } /* end */
1455};
1456
Kailang Yangccc656c2006-10-17 12:32:26 +02001457static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01001458 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1459 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1460 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1461 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02001462 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1463 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1464 { } /* end */
1465};
1466
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467/*
Takashi Iwai2134ea42008-01-10 16:53:55 +01001468 * virtual master controls
1469 */
1470
1471/*
1472 * slave controls for virtual master
1473 */
1474static const char *alc_slave_vols[] = {
1475 "Front Playback Volume",
1476 "Surround Playback Volume",
1477 "Center Playback Volume",
1478 "LFE Playback Volume",
1479 "Side Playback Volume",
1480 "Headphone Playback Volume",
1481 "Speaker Playback Volume",
1482 "Mono Playback Volume",
1483 "iSpeaker Playback Volume",
1484 "Line-Out Playback Volume",
1485 NULL,
1486};
1487
1488static const char *alc_slave_sws[] = {
1489 "Front Playback Switch",
1490 "Surround Playback Switch",
1491 "Center Playback Switch",
1492 "LFE Playback Switch",
1493 "Side Playback Switch",
1494 "Headphone Playback Switch",
1495 "Speaker Playback Switch",
1496 "Mono Playback Switch",
1497 "iSpeaker Playback Switch",
1498 NULL,
1499};
1500
1501/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001502 * build control elements
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 */
1504static int alc_build_controls(struct hda_codec *codec)
1505{
1506 struct alc_spec *spec = codec->spec;
1507 int err;
1508 int i;
1509
1510 for (i = 0; i < spec->num_mixers; i++) {
1511 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
1512 if (err < 0)
1513 return err;
1514 }
1515
1516 if (spec->multiout.dig_out_nid) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001517 err = snd_hda_create_spdif_out_ctls(codec,
1518 spec->multiout.dig_out_nid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 if (err < 0)
1520 return err;
1521 }
1522 if (spec->dig_in_nid) {
1523 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
1524 if (err < 0)
1525 return err;
1526 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01001527
1528 /* if we have no master control, let's create it */
1529 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
1530 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
1531 HDA_OUTPUT, spec->vmaster_tlv);
1532 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
1533 spec->vmaster_tlv, alc_slave_vols);
1534 if (err < 0)
1535 return err;
1536 }
1537 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
1538 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
1539 NULL, alc_slave_sws);
1540 if (err < 0)
1541 return err;
1542 }
1543
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 return 0;
1545}
1546
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001547
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548/*
1549 * initialize the codec volumes, etc
1550 */
1551
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001552/*
1553 * generic initialization of ADC, input mixers and output mixers
1554 */
1555static struct hda_verb alc880_volume_init_verbs[] = {
1556 /*
1557 * Unmute ADC0-2 and set the default input to mic-in
1558 */
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001559 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001560 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001561 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001562 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001563 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001564 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001566 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
1567 * mixer widget
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001568 * Note: PASD motherboards uses the Line In 2 as the input for front
1569 * panel mic (mic 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001571 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02001572 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1573 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1574 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
1575 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
1576 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
1577 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
1578 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001580 /*
1581 * Set up output mixers (0x0c - 0x0f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001583 /* set vol=0 to output mixers */
1584 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1585 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1586 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1587 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1588 /* set up input amps for analog loopback */
1589 /* Amp Indices: DAC = 0, mixer = 1 */
Takashi Iwai05acb862005-06-10 19:50:25 +02001590 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1591 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02001592 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1593 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02001594 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1595 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02001596 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1597 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598
1599 { }
1600};
1601
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001602/*
1603 * 3-stack pin configuration:
1604 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
1605 */
1606static struct hda_verb alc880_pin_3stack_init_verbs[] = {
1607 /*
1608 * preset connection lists of input pins
1609 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
1610 */
1611 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
1612 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1613 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
1614
1615 /*
1616 * Set pin mode and muting
1617 */
1618 /* set front pin widgets 0x14 for output */
1619 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1620 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1621 /* Mic1 (rear panel) pin widget for input and vref at 80% */
1622 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1623 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1624 /* Mic2 (as headphone out) for HP output */
1625 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1626 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1627 /* Line In pin widget for input */
1628 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1629 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1630 /* Line2 (as front mic) pin widget for input and vref at 80% */
1631 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1632 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1633 /* CD pin widget for input */
1634 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1635
1636 { }
1637};
1638
1639/*
1640 * 5-stack pin configuration:
1641 * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
1642 * line-in/side = 0x1a, f-mic = 0x1b
1643 */
1644static struct hda_verb alc880_pin_5stack_init_verbs[] = {
1645 /*
1646 * preset connection lists of input pins
1647 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
1648 */
1649 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1650 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
1651
1652 /*
1653 * Set pin mode and muting
1654 */
1655 /* set pin widgets 0x14-0x17 for output */
Takashi Iwai05acb862005-06-10 19:50:25 +02001656 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1657 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1658 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1659 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001660 /* unmute pins for output (no gain on this amp) */
1661 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1662 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1663 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1664 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1665
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02001667 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001668 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1669 /* Mic2 (as headphone out) for HP output */
1670 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02001671 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001672 /* Line In pin widget for input */
1673 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1674 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1675 /* Line2 (as front mic) pin widget for input and vref at 80% */
1676 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1677 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1678 /* CD pin widget for input */
1679 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680
1681 { }
1682};
1683
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001684/*
1685 * W810 pin configuration:
1686 * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
1687 */
1688static struct hda_verb alc880_pin_w810_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 /* hphone/speaker input selector: front DAC */
1690 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
1691
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001692 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1693 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1694 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1695 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1696 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1697 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1698
1699 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02001700 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 { }
1703};
1704
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001705/*
1706 * Z71V pin configuration:
1707 * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
1708 */
1709static struct hda_verb alc880_pin_z71v_init_verbs[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02001710 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001711 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai05acb862005-06-10 19:50:25 +02001712 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001713 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001714
Takashi Iwai16ded522005-06-10 19:58:24 +02001715 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001716 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02001717 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001718 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001719
1720 { }
1721};
1722
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001723/*
1724 * 6-stack pin configuration:
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001725 * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
1726 * f-mic = 0x19, line = 0x1a, HP = 0x1b
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001727 */
1728static struct hda_verb alc880_pin_6stack_init_verbs[] = {
1729 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1730
Takashi Iwai16ded522005-06-10 19:58:24 +02001731 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001732 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001733 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001734 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001735 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001736 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001737 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001738 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1739
Takashi Iwai16ded522005-06-10 19:58:24 +02001740 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001741 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001742 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001743 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001744 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001745 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001746 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai16ded522005-06-10 19:58:24 +02001747 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001748 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1749
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001750 { }
1751};
Takashi Iwai16ded522005-06-10 19:58:24 +02001752
Kailang Yangccc656c2006-10-17 12:32:26 +02001753/*
1754 * Uniwill pin configuration:
1755 * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
1756 * line = 0x1a
1757 */
1758static struct hda_verb alc880_uniwill_init_verbs[] = {
1759 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1760
1761 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1762 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1763 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1764 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1765 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1766 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1767 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1768 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1769 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1770 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1771 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1772 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1773 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1774 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1775
1776 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1777 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1778 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1779 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1780 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1781 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1782 /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
1783 /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
1784 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1785
1786 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
1787 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
1788
1789 { }
1790};
1791
1792/*
1793* Uniwill P53
1794* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
1795 */
1796static struct hda_verb alc880_uniwill_p53_init_verbs[] = {
1797 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1798
1799 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1800 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1801 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1802 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1803 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1804 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1805 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1806 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1807 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1808 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1809 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1810 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1811
1812 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1813 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1814 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1815 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1816 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1817 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1818
1819 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
1820 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT},
1821
1822 { }
1823};
1824
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01001825static struct hda_verb alc880_beep_init_verbs[] = {
1826 { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
1827 { }
1828};
1829
Kailang Yangccc656c2006-10-17 12:32:26 +02001830/* toggle speaker-output according to the hp-jack state */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02001831static void alc880_uniwill_hp_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02001832{
1833 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001834 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02001835
1836 present = snd_hda_codec_read(codec, 0x14, 0,
1837 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02001838 bits = present ? HDA_AMP_MUTE : 0;
1839 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
1840 HDA_AMP_MUTE, bits);
1841 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
1842 HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02001843}
1844
1845/* auto-toggle front mic */
1846static void alc880_uniwill_mic_automute(struct hda_codec *codec)
1847{
1848 unsigned int present;
1849 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02001850
1851 present = snd_hda_codec_read(codec, 0x18, 0,
1852 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02001853 bits = present ? HDA_AMP_MUTE : 0;
1854 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02001855}
1856
1857static void alc880_uniwill_automute(struct hda_codec *codec)
1858{
1859 alc880_uniwill_hp_automute(codec);
1860 alc880_uniwill_mic_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02001861}
1862
1863static void alc880_uniwill_unsol_event(struct hda_codec *codec,
1864 unsigned int res)
1865{
1866 /* Looks like the unsol event is incompatible with the standard
1867 * definition. 4bit tag is placed at 28 bit!
1868 */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02001869 switch (res >> 28) {
1870 case ALC880_HP_EVENT:
1871 alc880_uniwill_hp_automute(codec);
1872 break;
1873 case ALC880_MIC_EVENT:
1874 alc880_uniwill_mic_automute(codec);
1875 break;
1876 }
Kailang Yangccc656c2006-10-17 12:32:26 +02001877}
1878
1879static void alc880_uniwill_p53_hp_automute(struct hda_codec *codec)
1880{
1881 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001882 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02001883
1884 present = snd_hda_codec_read(codec, 0x14, 0,
1885 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02001886 bits = present ? HDA_AMP_MUTE : 0;
1887 snd_hda_codec_amp_stereo(codec, 0x15, HDA_INPUT, 0, HDA_AMP_MUTE, bits);
Kailang Yangccc656c2006-10-17 12:32:26 +02001888}
1889
1890static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
1891{
1892 unsigned int present;
1893
1894 present = snd_hda_codec_read(codec, 0x21, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02001895 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
1896 present &= HDA_AMP_VOLMASK;
1897 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0,
1898 HDA_AMP_VOLMASK, present);
1899 snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0,
1900 HDA_AMP_VOLMASK, present);
Kailang Yangccc656c2006-10-17 12:32:26 +02001901}
Takashi Iwai47fd8302007-08-10 17:11:07 +02001902
Kailang Yangccc656c2006-10-17 12:32:26 +02001903static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
1904 unsigned int res)
1905{
1906 /* Looks like the unsol event is incompatible with the standard
1907 * definition. 4bit tag is placed at 28 bit!
1908 */
1909 if ((res >> 28) == ALC880_HP_EVENT)
1910 alc880_uniwill_p53_hp_automute(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001911 if ((res >> 28) == ALC880_DCVOL_EVENT)
Kailang Yangccc656c2006-10-17 12:32:26 +02001912 alc880_uniwill_p53_dcvol_automute(codec);
1913}
1914
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001915/* FIXME! */
1916/*
1917 * F1734 pin configuration:
1918 * HP = 0x14, speaker-out = 0x15, mic = 0x18
1919 */
1920static struct hda_verb alc880_pin_f1734_init_verbs[] = {
1921 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
1922 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
1923 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
1924 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
1925
1926 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1927 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1928 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1929 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1930
1931 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1932 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1933 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1934 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1935 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1936 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1937 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1938 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1939 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02001940
1941 { }
1942};
1943
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001944/* FIXME! */
1945/*
1946 * ASUS pin configuration:
1947 * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
1948 */
1949static struct hda_verb alc880_pin_asus_init_verbs[] = {
1950 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
1951 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
1952 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
1953 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
1954
1955 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1956 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1957 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1958 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1959 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1960 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1961 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1962 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1963
1964 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1965 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1966 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1967 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1968 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1969 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1970 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1971 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1972 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1973
1974 { }
1975};
1976
1977/* Enable GPIO mask and set output */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001978#define alc880_gpio1_init_verbs alc_gpio1_init_verbs
1979#define alc880_gpio2_init_verbs alc_gpio2_init_verbs
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001980
Kailang Yangdf694da2005-12-05 19:42:22 +01001981/* Clevo m520g init */
1982static struct hda_verb alc880_pin_clevo_init_verbs[] = {
1983 /* headphone output */
1984 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
1985 /* line-out */
1986 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1987 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1988 /* Line-in */
1989 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1990 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1991 /* CD */
1992 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1993 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1994 /* Mic1 (rear panel) */
1995 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1996 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1997 /* Mic2 (front panel) */
1998 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1999 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2000 /* headphone */
2001 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2002 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2003 /* change to EAPD mode */
2004 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2005 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2006
2007 { }
2008};
2009
2010static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02002011 /* change to EAPD mode */
2012 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2013 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2014
Kailang Yangdf694da2005-12-05 19:42:22 +01002015 /* Headphone output */
2016 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2017 /* Front output*/
2018 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2019 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
2020
2021 /* Line In pin widget for input */
2022 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2023 /* CD pin widget for input */
2024 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2025 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2026 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2027
2028 /* change to EAPD mode */
2029 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2030 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
2031
2032 { }
2033};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002034
2035/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002036 * LG m1 express dual
2037 *
2038 * Pin assignment:
2039 * Rear Line-In/Out (blue): 0x14
2040 * Build-in Mic-In: 0x15
2041 * Speaker-out: 0x17
2042 * HP-Out (green): 0x1b
2043 * Mic-In/Out (red): 0x19
2044 * SPDIF-Out: 0x1e
2045 */
2046
2047/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
2048static hda_nid_t alc880_lg_dac_nids[3] = {
2049 0x05, 0x02, 0x03
2050};
2051
2052/* seems analog CD is not working */
2053static struct hda_input_mux alc880_lg_capture_source = {
2054 .num_items = 3,
2055 .items = {
2056 { "Mic", 0x1 },
2057 { "Line", 0x5 },
2058 { "Internal Mic", 0x6 },
2059 },
2060};
2061
2062/* 2,4,6 channel modes */
2063static struct hda_verb alc880_lg_ch2_init[] = {
2064 /* set line-in and mic-in to input */
2065 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2066 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2067 { }
2068};
2069
2070static struct hda_verb alc880_lg_ch4_init[] = {
2071 /* set line-in to out and mic-in to input */
2072 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2073 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2074 { }
2075};
2076
2077static struct hda_verb alc880_lg_ch6_init[] = {
2078 /* set line-in and mic-in to output */
2079 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2080 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2081 { }
2082};
2083
2084static struct hda_channel_mode alc880_lg_ch_modes[3] = {
2085 { 2, alc880_lg_ch2_init },
2086 { 4, alc880_lg_ch4_init },
2087 { 6, alc880_lg_ch6_init },
2088};
2089
2090static struct snd_kcontrol_new alc880_lg_mixer[] = {
2091 /* FIXME: it's not really "master" but front channels */
Takashi Iwai2134ea42008-01-10 16:53:55 +01002092 HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2093 HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002094 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2095 HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
2096 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
2097 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
2098 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
2099 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
2100 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2101 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
2102 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT),
2103 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT),
2104 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT),
2105 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT),
2106 {
2107 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2108 .name = "Channel Mode",
2109 .info = alc_ch_mode_info,
2110 .get = alc_ch_mode_get,
2111 .put = alc_ch_mode_put,
2112 },
2113 { } /* end */
2114};
2115
2116static struct hda_verb alc880_lg_init_verbs[] = {
2117 /* set capture source to mic-in */
2118 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2119 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2120 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2121 /* mute all amp mixer inputs */
2122 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02002123 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2124 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002125 /* line-in to input */
2126 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2127 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2128 /* built-in mic */
2129 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2130 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2131 /* speaker-out */
2132 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2133 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2134 /* mic-in to input */
2135 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
2136 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2137 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2138 /* HP-out */
2139 {0x13, AC_VERB_SET_CONNECT_SEL, 0x03},
2140 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2141 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2142 /* jack sense */
2143 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1},
2144 { }
2145};
2146
2147/* toggle speaker-output according to the hp-jack state */
2148static void alc880_lg_automute(struct hda_codec *codec)
2149{
2150 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002151 unsigned char bits;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002152
2153 present = snd_hda_codec_read(codec, 0x1b, 0,
2154 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002155 bits = present ? HDA_AMP_MUTE : 0;
2156 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
2157 HDA_AMP_MUTE, bits);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002158}
2159
2160static void alc880_lg_unsol_event(struct hda_codec *codec, unsigned int res)
2161{
2162 /* Looks like the unsol event is incompatible with the standard
2163 * definition. 4bit tag is placed at 28 bit!
2164 */
2165 if ((res >> 28) == 0x01)
2166 alc880_lg_automute(codec);
2167}
2168
2169/*
Takashi Iwaid6815182006-03-23 16:06:23 +01002170 * LG LW20
2171 *
2172 * Pin assignment:
2173 * Speaker-out: 0x14
2174 * Mic-In: 0x18
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002175 * Built-in Mic-In: 0x19
2176 * Line-In: 0x1b
2177 * HP-Out: 0x1a
Takashi Iwaid6815182006-03-23 16:06:23 +01002178 * SPDIF-Out: 0x1e
2179 */
2180
Takashi Iwaid6815182006-03-23 16:06:23 +01002181static struct hda_input_mux alc880_lg_lw_capture_source = {
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002182 .num_items = 3,
Takashi Iwaid6815182006-03-23 16:06:23 +01002183 .items = {
2184 { "Mic", 0x0 },
2185 { "Internal Mic", 0x1 },
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002186 { "Line In", 0x2 },
Takashi Iwaid6815182006-03-23 16:06:23 +01002187 },
2188};
2189
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002190#define alc880_lg_lw_modes alc880_threestack_modes
2191
Takashi Iwaid6815182006-03-23 16:06:23 +01002192static struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002193 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2194 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2195 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2196 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
2197 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2198 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2199 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2200 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2201 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2202 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaid6815182006-03-23 16:06:23 +01002203 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2204 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2205 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
2206 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002207 {
2208 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2209 .name = "Channel Mode",
2210 .info = alc_ch_mode_info,
2211 .get = alc_ch_mode_get,
2212 .put = alc_ch_mode_put,
2213 },
Takashi Iwaid6815182006-03-23 16:06:23 +01002214 { } /* end */
2215};
2216
2217static struct hda_verb alc880_lg_lw_init_verbs[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002218 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2219 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
2220 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
2221
Takashi Iwaid6815182006-03-23 16:06:23 +01002222 /* set capture source to mic-in */
2223 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2224 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2225 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02002226 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaid6815182006-03-23 16:06:23 +01002227 /* speaker-out */
2228 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2229 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2230 /* HP-out */
Takashi Iwaid6815182006-03-23 16:06:23 +01002231 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2232 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2233 /* mic-in to input */
2234 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2235 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2236 /* built-in mic */
2237 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2238 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2239 /* jack sense */
2240 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1},
2241 { }
2242};
2243
2244/* toggle speaker-output according to the hp-jack state */
2245static void alc880_lg_lw_automute(struct hda_codec *codec)
2246{
2247 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002248 unsigned char bits;
Takashi Iwaid6815182006-03-23 16:06:23 +01002249
2250 present = snd_hda_codec_read(codec, 0x1b, 0,
2251 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002252 bits = present ? HDA_AMP_MUTE : 0;
2253 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
2254 HDA_AMP_MUTE, bits);
Takashi Iwaid6815182006-03-23 16:06:23 +01002255}
2256
2257static void alc880_lg_lw_unsol_event(struct hda_codec *codec, unsigned int res)
2258{
2259 /* Looks like the unsol event is incompatible with the standard
2260 * definition. 4bit tag is placed at 28 bit!
2261 */
2262 if ((res >> 28) == 0x01)
2263 alc880_lg_lw_automute(codec);
2264}
2265
Takashi Iwaicb53c622007-08-10 17:21:45 +02002266#ifdef CONFIG_SND_HDA_POWER_SAVE
2267static struct hda_amp_list alc880_loopbacks[] = {
2268 { 0x0b, HDA_INPUT, 0 },
2269 { 0x0b, HDA_INPUT, 1 },
2270 { 0x0b, HDA_INPUT, 2 },
2271 { 0x0b, HDA_INPUT, 3 },
2272 { 0x0b, HDA_INPUT, 4 },
2273 { } /* end */
2274};
2275
2276static struct hda_amp_list alc880_lg_loopbacks[] = {
2277 { 0x0b, HDA_INPUT, 1 },
2278 { 0x0b, HDA_INPUT, 6 },
2279 { 0x0b, HDA_INPUT, 7 },
2280 { } /* end */
2281};
2282#endif
2283
Takashi Iwaid6815182006-03-23 16:06:23 +01002284/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002285 * Common callbacks
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002286 */
Takashi Iwai16ded522005-06-10 19:58:24 +02002287
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288static int alc_init(struct hda_codec *codec)
2289{
2290 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002291 unsigned int i;
2292
2293 for (i = 0; i < spec->num_init_verbs; i++)
2294 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002295
2296 if (spec->init_hook)
2297 spec->init_hook(codec);
2298
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299 return 0;
2300}
2301
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002302static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
2303{
2304 struct alc_spec *spec = codec->spec;
2305
2306 if (spec->unsol_event)
2307 spec->unsol_event(codec, res);
2308}
2309
Takashi Iwaicb53c622007-08-10 17:21:45 +02002310#ifdef CONFIG_SND_HDA_POWER_SAVE
2311static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
2312{
2313 struct alc_spec *spec = codec->spec;
2314 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
2315}
2316#endif
2317
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318/*
2319 * Analog playback callbacks
2320 */
2321static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
2322 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002323 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324{
2325 struct alc_spec *spec = codec->spec;
2326 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
2327}
2328
2329static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2330 struct hda_codec *codec,
2331 unsigned int stream_tag,
2332 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002333 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002334{
2335 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002336 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
2337 stream_tag, format, substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338}
2339
2340static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
2341 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002342 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343{
2344 struct alc_spec *spec = codec->spec;
2345 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
2346}
2347
2348/*
2349 * Digital out
2350 */
2351static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
2352 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002353 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354{
2355 struct alc_spec *spec = codec->spec;
2356 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
2357}
2358
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002359static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2360 struct hda_codec *codec,
2361 unsigned int stream_tag,
2362 unsigned int format,
2363 struct snd_pcm_substream *substream)
2364{
2365 struct alc_spec *spec = codec->spec;
2366 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
2367 stream_tag, format, substream);
2368}
2369
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
2371 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002372 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373{
2374 struct alc_spec *spec = codec->spec;
2375 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
2376}
2377
2378/*
2379 * Analog capture
2380 */
2381static int alc880_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
2382 struct hda_codec *codec,
2383 unsigned int stream_tag,
2384 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002385 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386{
2387 struct alc_spec *spec = codec->spec;
2388
2389 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
2390 stream_tag, 0, format);
2391 return 0;
2392}
2393
2394static int alc880_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
2395 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002396 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397{
2398 struct alc_spec *spec = codec->spec;
2399
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002400 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
2401 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402 return 0;
2403}
2404
2405
2406/*
2407 */
2408static struct hda_pcm_stream alc880_pcm_analog_playback = {
2409 .substreams = 1,
2410 .channels_min = 2,
2411 .channels_max = 8,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002412 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413 .ops = {
2414 .open = alc880_playback_pcm_open,
2415 .prepare = alc880_playback_pcm_prepare,
2416 .cleanup = alc880_playback_pcm_cleanup
2417 },
2418};
2419
2420static struct hda_pcm_stream alc880_pcm_analog_capture = {
2421 .substreams = 2,
2422 .channels_min = 2,
2423 .channels_max = 2,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002424 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425 .ops = {
2426 .prepare = alc880_capture_pcm_prepare,
2427 .cleanup = alc880_capture_pcm_cleanup
2428 },
2429};
2430
2431static struct hda_pcm_stream alc880_pcm_digital_playback = {
2432 .substreams = 1,
2433 .channels_min = 2,
2434 .channels_max = 2,
2435 /* NID is set in alc_build_pcms */
2436 .ops = {
2437 .open = alc880_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002438 .close = alc880_dig_playback_pcm_close,
2439 .prepare = alc880_dig_playback_pcm_prepare
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440 },
2441};
2442
2443static struct hda_pcm_stream alc880_pcm_digital_capture = {
2444 .substreams = 1,
2445 .channels_min = 2,
2446 .channels_max = 2,
2447 /* NID is set in alc_build_pcms */
2448};
2449
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01002450/* Used by alc_build_pcms to flag that a PCM has no playback stream */
2451static struct hda_pcm_stream alc_pcm_null_playback = {
2452 .substreams = 0,
2453 .channels_min = 0,
2454 .channels_max = 0,
2455};
2456
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457static int alc_build_pcms(struct hda_codec *codec)
2458{
2459 struct alc_spec *spec = codec->spec;
2460 struct hda_pcm *info = spec->pcm_rec;
2461 int i;
2462
2463 codec->num_pcms = 1;
2464 codec->pcm_info = info;
2465
2466 info->name = spec->stream_name_analog;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002467 if (spec->stream_analog_playback) {
2468 snd_assert(spec->multiout.dac_nids, return -EINVAL);
2469 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
2470 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
2471 }
2472 if (spec->stream_analog_capture) {
2473 snd_assert(spec->adc_nids, return -EINVAL);
2474 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
2475 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
2476 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477
Takashi Iwai4a471b72005-12-07 13:56:29 +01002478 if (spec->channel_mode) {
2479 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
2480 for (i = 0; i < spec->num_channel_mode; i++) {
2481 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
2482 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
2483 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484 }
2485 }
2486
Takashi Iwaie08a0072006-09-07 17:52:14 +02002487 /* SPDIF for stream index #1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02002489 codec->num_pcms = 2;
Takashi Iwaic06134d2006-10-11 18:49:13 +02002490 info = spec->pcm_rec + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491 info->name = spec->stream_name_digital;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002492 if (spec->multiout.dig_out_nid &&
2493 spec->stream_digital_playback) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
2495 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
2496 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01002497 if (spec->dig_in_nid &&
2498 spec->stream_digital_capture) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
2500 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
2501 }
2502 }
2503
Takashi Iwaie08a0072006-09-07 17:52:14 +02002504 /* If the use of more than one ADC is requested for the current
2505 * model, configure a second analog capture-only PCM.
2506 */
2507 /* Additional Analaog capture for index #2 */
2508 if (spec->num_adc_nids > 1 && spec->stream_analog_capture &&
2509 spec->adc_nids) {
2510 codec->num_pcms = 3;
Takashi Iwaic06134d2006-10-11 18:49:13 +02002511 info = spec->pcm_rec + 2;
Takashi Iwaie08a0072006-09-07 17:52:14 +02002512 info->name = spec->stream_name_analog;
2513 /* No playback stream for second PCM */
2514 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = alc_pcm_null_playback;
2515 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
2516 if (spec->stream_analog_capture) {
2517 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
2518 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[1];
2519 }
2520 }
2521
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522 return 0;
2523}
2524
2525static void alc_free(struct hda_codec *codec)
2526{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002527 struct alc_spec *spec = codec->spec;
2528 unsigned int i;
2529
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002530 if (!spec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002531 return;
2532
2533 if (spec->kctl_alloc) {
2534 for (i = 0; i < spec->num_kctl_used; i++)
2535 kfree(spec->kctl_alloc[i].name);
2536 kfree(spec->kctl_alloc);
2537 }
2538 kfree(spec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539}
2540
2541/*
2542 */
2543static struct hda_codec_ops alc_patch_ops = {
2544 .build_controls = alc_build_controls,
2545 .build_pcms = alc_build_pcms,
2546 .init = alc_init,
2547 .free = alc_free,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002548 .unsol_event = alc_unsol_event,
Takashi Iwaicb53c622007-08-10 17:21:45 +02002549#ifdef CONFIG_SND_HDA_POWER_SAVE
2550 .check_power_status = alc_check_power_status,
2551#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552};
2553
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002554
2555/*
2556 * Test configuration for debugging
2557 *
2558 * Almost all inputs/outputs are enabled. I/O pins can be configured via
2559 * enum controls.
2560 */
2561#ifdef CONFIG_SND_DEBUG
2562static hda_nid_t alc880_test_dac_nids[4] = {
2563 0x02, 0x03, 0x04, 0x05
2564};
2565
2566static struct hda_input_mux alc880_test_capture_source = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002567 .num_items = 7,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002568 .items = {
2569 { "In-1", 0x0 },
2570 { "In-2", 0x1 },
2571 { "In-3", 0x2 },
2572 { "In-4", 0x3 },
2573 { "CD", 0x4 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002574 { "Front", 0x5 },
2575 { "Surround", 0x6 },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002576 },
2577};
2578
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002579static struct hda_channel_mode alc880_test_modes[4] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002580 { 2, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02002581 { 4, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002582 { 6, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02002583 { 8, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002584};
2585
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002586static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
2587 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002588{
2589 static char *texts[] = {
2590 "N/A", "Line Out", "HP Out",
2591 "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
2592 };
2593 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2594 uinfo->count = 1;
2595 uinfo->value.enumerated.items = 8;
2596 if (uinfo->value.enumerated.item >= 8)
2597 uinfo->value.enumerated.item = 7;
2598 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
2599 return 0;
2600}
2601
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002602static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol,
2603 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002604{
2605 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2606 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
2607 unsigned int pin_ctl, item = 0;
2608
2609 pin_ctl = snd_hda_codec_read(codec, nid, 0,
2610 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
2611 if (pin_ctl & AC_PINCTL_OUT_EN) {
2612 if (pin_ctl & AC_PINCTL_HP_EN)
2613 item = 2;
2614 else
2615 item = 1;
2616 } else if (pin_ctl & AC_PINCTL_IN_EN) {
2617 switch (pin_ctl & AC_PINCTL_VREFEN) {
2618 case AC_PINCTL_VREF_HIZ: item = 3; break;
2619 case AC_PINCTL_VREF_50: item = 4; break;
2620 case AC_PINCTL_VREF_GRD: item = 5; break;
2621 case AC_PINCTL_VREF_80: item = 6; break;
2622 case AC_PINCTL_VREF_100: item = 7; break;
2623 }
2624 }
2625 ucontrol->value.enumerated.item[0] = item;
2626 return 0;
2627}
2628
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002629static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
2630 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002631{
2632 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2633 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
2634 static unsigned int ctls[] = {
2635 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
2636 AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
2637 AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
2638 AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
2639 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
2640 AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
2641 };
2642 unsigned int old_ctl, new_ctl;
2643
2644 old_ctl = snd_hda_codec_read(codec, nid, 0,
2645 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
2646 new_ctl = ctls[ucontrol->value.enumerated.item[0]];
2647 if (old_ctl != new_ctl) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002648 int val;
2649 snd_hda_codec_write_cache(codec, nid, 0,
2650 AC_VERB_SET_PIN_WIDGET_CONTROL,
2651 new_ctl);
Takashi Iwai47fd8302007-08-10 17:11:07 +02002652 val = ucontrol->value.enumerated.item[0] >= 3 ?
2653 HDA_AMP_MUTE : 0;
2654 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
2655 HDA_AMP_MUTE, val);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002656 return 1;
2657 }
2658 return 0;
2659}
2660
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002661static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
2662 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002663{
2664 static char *texts[] = {
2665 "Front", "Surround", "CLFE", "Side"
2666 };
2667 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2668 uinfo->count = 1;
2669 uinfo->value.enumerated.items = 4;
2670 if (uinfo->value.enumerated.item >= 4)
2671 uinfo->value.enumerated.item = 3;
2672 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
2673 return 0;
2674}
2675
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002676static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol,
2677 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002678{
2679 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2680 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
2681 unsigned int sel;
2682
2683 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
2684 ucontrol->value.enumerated.item[0] = sel & 3;
2685 return 0;
2686}
2687
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002688static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
2689 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002690{
2691 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2692 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
2693 unsigned int sel;
2694
2695 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
2696 if (ucontrol->value.enumerated.item[0] != sel) {
2697 sel = ucontrol->value.enumerated.item[0] & 3;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002698 snd_hda_codec_write_cache(codec, nid, 0,
2699 AC_VERB_SET_CONNECT_SEL, sel);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002700 return 1;
2701 }
2702 return 0;
2703}
2704
2705#define PIN_CTL_TEST(xname,nid) { \
2706 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2707 .name = xname, \
2708 .info = alc_test_pin_ctl_info, \
2709 .get = alc_test_pin_ctl_get, \
2710 .put = alc_test_pin_ctl_put, \
2711 .private_value = nid \
2712 }
2713
2714#define PIN_SRC_TEST(xname,nid) { \
2715 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2716 .name = xname, \
2717 .info = alc_test_pin_src_info, \
2718 .get = alc_test_pin_src_get, \
2719 .put = alc_test_pin_src_put, \
2720 .private_value = nid \
2721 }
2722
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002723static struct snd_kcontrol_new alc880_test_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02002724 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2725 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2726 HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
2727 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002728 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2729 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
2730 HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
2731 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002732 PIN_CTL_TEST("Front Pin Mode", 0x14),
2733 PIN_CTL_TEST("Surround Pin Mode", 0x15),
2734 PIN_CTL_TEST("CLFE Pin Mode", 0x16),
2735 PIN_CTL_TEST("Side Pin Mode", 0x17),
2736 PIN_CTL_TEST("In-1 Pin Mode", 0x18),
2737 PIN_CTL_TEST("In-2 Pin Mode", 0x19),
2738 PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
2739 PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
2740 PIN_SRC_TEST("In-1 Pin Source", 0x18),
2741 PIN_SRC_TEST("In-2 Pin Source", 0x19),
2742 PIN_SRC_TEST("In-3 Pin Source", 0x1a),
2743 PIN_SRC_TEST("In-4 Pin Source", 0x1b),
2744 HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
2745 HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
2746 HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
2747 HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
2748 HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
2749 HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
2750 HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
2751 HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
2752 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
2753 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002754 {
2755 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2756 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002757 .info = alc_ch_mode_info,
2758 .get = alc_ch_mode_get,
2759 .put = alc_ch_mode_put,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002760 },
2761 { } /* end */
2762};
2763
2764static struct hda_verb alc880_test_init_verbs[] = {
2765 /* Unmute inputs of 0x0c - 0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02002766 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2767 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2768 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2769 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2770 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2771 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2772 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2773 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002774 /* Vol output for 0x0c-0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02002775 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2776 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2777 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2778 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002779 /* Set output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02002780 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2781 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2782 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2783 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002784 /* Unmute output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02002785 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2786 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2787 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2788 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002789 /* Set input pins 0x18-0x1c */
Takashi Iwai16ded522005-06-10 19:58:24 +02002790 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2791 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai05acb862005-06-10 19:50:25 +02002792 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2793 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2794 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002795 /* Mute input pins 0x18-0x1b */
Takashi Iwai05acb862005-06-10 19:50:25 +02002796 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2797 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2798 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2799 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002800 /* ADC set up */
Takashi Iwai05acb862005-06-10 19:50:25 +02002801 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002802 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02002803 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002804 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02002805 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002806 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02002807 /* Analog input/passthru */
2808 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2809 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2810 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2811 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2812 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002813 { }
2814};
2815#endif
2816
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817/*
2818 */
2819
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002820static const char *alc880_models[ALC880_MODEL_LAST] = {
2821 [ALC880_3ST] = "3stack",
2822 [ALC880_TCL_S700] = "tcl",
2823 [ALC880_3ST_DIG] = "3stack-digout",
2824 [ALC880_CLEVO] = "clevo",
2825 [ALC880_5ST] = "5stack",
2826 [ALC880_5ST_DIG] = "5stack-digout",
2827 [ALC880_W810] = "w810",
2828 [ALC880_Z71V] = "z71v",
2829 [ALC880_6ST] = "6stack",
2830 [ALC880_6ST_DIG] = "6stack-digout",
2831 [ALC880_ASUS] = "asus",
2832 [ALC880_ASUS_W1V] = "asus-w1v",
2833 [ALC880_ASUS_DIG] = "asus-dig",
2834 [ALC880_ASUS_DIG2] = "asus-dig2",
2835 [ALC880_UNIWILL_DIG] = "uniwill",
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01002836 [ALC880_UNIWILL_P53] = "uniwill-p53",
2837 [ALC880_FUJITSU] = "fujitsu",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002838 [ALC880_F1734] = "F1734",
2839 [ALC880_LG] = "lg",
2840 [ALC880_LG_LW] = "lg-lw",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002841#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002842 [ALC880_TEST] = "test",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002843#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002844 [ALC880_AUTO] = "auto",
2845};
2846
2847static struct snd_pci_quirk alc880_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002848 SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002849 SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
2850 SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
2851 SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
2852 SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
2853 SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
2854 SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
2855 SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
2856 SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002857 SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
2858 SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002859 SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
2860 SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
2861 SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
2862 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
2863 SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
2864 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
2865 SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
2866 /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
2867 SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
2868 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
Tobin Davis0e4ceb72007-01-08 10:54:26 +01002869 SND_PCI_QUIRK(0x1043, 0x814e, "ASUS", ALC880_ASUS),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002870 SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
2871 SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
2872 SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002873 SND_PCI_QUIRK(0x1043, 0, "ASUS", ALC880_ASUS), /* default ASUS */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002874 SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002875 SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
2876 SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002877 SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
2878 SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002879 SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
2880 SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
2881 SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
2882 SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002883 SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
2884 SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002885 SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002886 SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002887 SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002888 SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002889 SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
2890 SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002891 SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
2892 SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002893 SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002894 SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002895 SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01002896 SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002897 SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002898 SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
2899 SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002900 SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002901 SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
2902 SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
2903 SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
2904 SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002905 SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
2906 SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002907 SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002908 SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002909 SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
2910 SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002911 SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
2912 SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
2913 SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002914 SND_PCI_QUIRK(0x8086, 0, "Intel mobo", ALC880_3ST), /* default Intel */
2915 SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
2916 SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917 {}
2918};
2919
Takashi Iwai16ded522005-06-10 19:58:24 +02002920/*
Kailang Yangdf694da2005-12-05 19:42:22 +01002921 * ALC880 codec presets
Takashi Iwai16ded522005-06-10 19:58:24 +02002922 */
Takashi Iwai16ded522005-06-10 19:58:24 +02002923static struct alc_config_preset alc880_presets[] = {
2924 [ALC880_3ST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002925 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002926 .init_verbs = { alc880_volume_init_verbs,
2927 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02002928 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02002929 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02002930 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
2931 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02002932 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02002933 .input_mux = &alc880_capture_source,
2934 },
2935 [ALC880_3ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002936 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002937 .init_verbs = { alc880_volume_init_verbs,
2938 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02002939 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02002940 .dac_nids = alc880_dac_nids,
2941 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02002942 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
2943 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02002944 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02002945 .input_mux = &alc880_capture_source,
2946 },
Kailang Yangdf694da2005-12-05 19:42:22 +01002947 [ALC880_TCL_S700] = {
2948 .mixers = { alc880_tcl_s700_mixer },
2949 .init_verbs = { alc880_volume_init_verbs,
2950 alc880_pin_tcl_S700_init_verbs,
2951 alc880_gpio2_init_verbs },
2952 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
2953 .dac_nids = alc880_dac_nids,
2954 .hp_nid = 0x03,
2955 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
2956 .channel_mode = alc880_2_jack_modes,
2957 .input_mux = &alc880_capture_source,
2958 },
Takashi Iwai16ded522005-06-10 19:58:24 +02002959 [ALC880_5ST] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002960 .mixers = { alc880_three_stack_mixer,
2961 alc880_five_stack_mixer},
2962 .init_verbs = { alc880_volume_init_verbs,
2963 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02002964 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
2965 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02002966 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
2967 .channel_mode = alc880_fivestack_modes,
2968 .input_mux = &alc880_capture_source,
2969 },
2970 [ALC880_5ST_DIG] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002971 .mixers = { alc880_three_stack_mixer,
2972 alc880_five_stack_mixer },
2973 .init_verbs = { alc880_volume_init_verbs,
2974 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02002975 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
2976 .dac_nids = alc880_dac_nids,
2977 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02002978 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
2979 .channel_mode = alc880_fivestack_modes,
2980 .input_mux = &alc880_capture_source,
2981 },
Takashi Iwaib6482d42005-06-27 15:32:43 +02002982 [ALC880_6ST] = {
2983 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002984 .init_verbs = { alc880_volume_init_verbs,
2985 alc880_pin_6stack_init_verbs },
Takashi Iwaib6482d42005-06-27 15:32:43 +02002986 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
2987 .dac_nids = alc880_6st_dac_nids,
2988 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
2989 .channel_mode = alc880_sixstack_modes,
2990 .input_mux = &alc880_6stack_capture_source,
2991 },
Takashi Iwai16ded522005-06-10 19:58:24 +02002992 [ALC880_6ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002993 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002994 .init_verbs = { alc880_volume_init_verbs,
2995 alc880_pin_6stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02002996 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
2997 .dac_nids = alc880_6st_dac_nids,
2998 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02002999 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
3000 .channel_mode = alc880_sixstack_modes,
3001 .input_mux = &alc880_6stack_capture_source,
3002 },
3003 [ALC880_W810] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003004 .mixers = { alc880_w810_base_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003005 .init_verbs = { alc880_volume_init_verbs,
3006 alc880_pin_w810_init_verbs,
Takashi Iwaib0af0de2005-06-21 14:49:19 +02003007 alc880_gpio2_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003008 .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
3009 .dac_nids = alc880_w810_dac_nids,
3010 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003011 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
3012 .channel_mode = alc880_w810_modes,
3013 .input_mux = &alc880_capture_source,
3014 },
3015 [ALC880_Z71V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003016 .mixers = { alc880_z71v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003017 .init_verbs = { alc880_volume_init_verbs,
3018 alc880_pin_z71v_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003019 .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
3020 .dac_nids = alc880_z71v_dac_nids,
3021 .dig_out_nid = ALC880_DIGOUT_NID,
3022 .hp_nid = 0x03,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003023 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3024 .channel_mode = alc880_2_jack_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02003025 .input_mux = &alc880_capture_source,
3026 },
3027 [ALC880_F1734] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003028 .mixers = { alc880_f1734_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003029 .init_verbs = { alc880_volume_init_verbs,
3030 alc880_pin_f1734_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003031 .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
3032 .dac_nids = alc880_f1734_dac_nids,
3033 .hp_nid = 0x02,
3034 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3035 .channel_mode = alc880_2_jack_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02003036 .input_mux = &alc880_capture_source,
3037 },
3038 [ALC880_ASUS] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003039 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003040 .init_verbs = { alc880_volume_init_verbs,
3041 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003042 alc880_gpio1_init_verbs },
3043 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3044 .dac_nids = alc880_asus_dac_nids,
3045 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3046 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003047 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003048 .input_mux = &alc880_capture_source,
3049 },
3050 [ALC880_ASUS_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003051 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003052 .init_verbs = { alc880_volume_init_verbs,
3053 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003054 alc880_gpio1_init_verbs },
3055 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3056 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003057 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003058 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3059 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003060 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003061 .input_mux = &alc880_capture_source,
3062 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003063 [ALC880_ASUS_DIG2] = {
3064 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003065 .init_verbs = { alc880_volume_init_verbs,
3066 alc880_pin_asus_init_verbs,
Kailang Yangdf694da2005-12-05 19:42:22 +01003067 alc880_gpio2_init_verbs }, /* use GPIO2 */
3068 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3069 .dac_nids = alc880_asus_dac_nids,
3070 .dig_out_nid = ALC880_DIGOUT_NID,
3071 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3072 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003073 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01003074 .input_mux = &alc880_capture_source,
3075 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003076 [ALC880_ASUS_W1V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003077 .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003078 .init_verbs = { alc880_volume_init_verbs,
3079 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003080 alc880_gpio1_init_verbs },
3081 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3082 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003083 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003084 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3085 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003086 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003087 .input_mux = &alc880_capture_source,
3088 },
3089 [ALC880_UNIWILL_DIG] = {
Takashi Iwai3c10a9d2005-08-23 20:02:27 +02003090 .mixers = { alc880_asus_mixer, alc880_pcbeep_mixer },
Kailang Yangccc656c2006-10-17 12:32:26 +02003091 .init_verbs = { alc880_volume_init_verbs,
3092 alc880_pin_asus_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003093 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3094 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003095 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003096 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3097 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003098 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003099 .input_mux = &alc880_capture_source,
3100 },
Kailang Yangccc656c2006-10-17 12:32:26 +02003101 [ALC880_UNIWILL] = {
3102 .mixers = { alc880_uniwill_mixer },
3103 .init_verbs = { alc880_volume_init_verbs,
3104 alc880_uniwill_init_verbs },
3105 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3106 .dac_nids = alc880_asus_dac_nids,
3107 .dig_out_nid = ALC880_DIGOUT_NID,
3108 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3109 .channel_mode = alc880_threestack_modes,
3110 .need_dac_fix = 1,
3111 .input_mux = &alc880_capture_source,
3112 .unsol_event = alc880_uniwill_unsol_event,
3113 .init_hook = alc880_uniwill_automute,
3114 },
3115 [ALC880_UNIWILL_P53] = {
3116 .mixers = { alc880_uniwill_p53_mixer },
3117 .init_verbs = { alc880_volume_init_verbs,
3118 alc880_uniwill_p53_init_verbs },
3119 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3120 .dac_nids = alc880_asus_dac_nids,
3121 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003122 .channel_mode = alc880_threestack_modes,
3123 .input_mux = &alc880_capture_source,
3124 .unsol_event = alc880_uniwill_p53_unsol_event,
3125 .init_hook = alc880_uniwill_p53_hp_automute,
3126 },
3127 [ALC880_FUJITSU] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003128 .mixers = { alc880_fujitsu_mixer,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003129 alc880_pcbeep_mixer, },
3130 .init_verbs = { alc880_volume_init_verbs,
3131 alc880_uniwill_p53_init_verbs,
3132 alc880_beep_init_verbs },
3133 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3134 .dac_nids = alc880_dac_nids,
Takashi Iwaid53d7d92007-08-20 15:20:02 +02003135 .dig_out_nid = ALC880_DIGOUT_NID,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003136 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3137 .channel_mode = alc880_2_jack_modes,
Kailang Yangccc656c2006-10-17 12:32:26 +02003138 .input_mux = &alc880_capture_source,
3139 .unsol_event = alc880_uniwill_p53_unsol_event,
3140 .init_hook = alc880_uniwill_p53_hp_automute,
3141 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003142 [ALC880_CLEVO] = {
3143 .mixers = { alc880_three_stack_mixer },
3144 .init_verbs = { alc880_volume_init_verbs,
3145 alc880_pin_clevo_init_verbs },
3146 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3147 .dac_nids = alc880_dac_nids,
3148 .hp_nid = 0x03,
3149 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3150 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003151 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01003152 .input_mux = &alc880_capture_source,
3153 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003154 [ALC880_LG] = {
3155 .mixers = { alc880_lg_mixer },
3156 .init_verbs = { alc880_volume_init_verbs,
3157 alc880_lg_init_verbs },
3158 .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids),
3159 .dac_nids = alc880_lg_dac_nids,
3160 .dig_out_nid = ALC880_DIGOUT_NID,
3161 .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
3162 .channel_mode = alc880_lg_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003163 .need_dac_fix = 1,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003164 .input_mux = &alc880_lg_capture_source,
3165 .unsol_event = alc880_lg_unsol_event,
3166 .init_hook = alc880_lg_automute,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003167#ifdef CONFIG_SND_HDA_POWER_SAVE
3168 .loopbacks = alc880_lg_loopbacks,
3169#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003170 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003171 [ALC880_LG_LW] = {
3172 .mixers = { alc880_lg_lw_mixer },
3173 .init_verbs = { alc880_volume_init_verbs,
3174 alc880_lg_lw_init_verbs },
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003175 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwaid6815182006-03-23 16:06:23 +01003176 .dac_nids = alc880_dac_nids,
3177 .dig_out_nid = ALC880_DIGOUT_NID,
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003178 .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
3179 .channel_mode = alc880_lg_lw_modes,
Takashi Iwaid6815182006-03-23 16:06:23 +01003180 .input_mux = &alc880_lg_lw_capture_source,
3181 .unsol_event = alc880_lg_lw_unsol_event,
3182 .init_hook = alc880_lg_lw_automute,
3183 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003184#ifdef CONFIG_SND_DEBUG
3185 [ALC880_TEST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003186 .mixers = { alc880_test_mixer },
3187 .init_verbs = { alc880_test_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003188 .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
3189 .dac_nids = alc880_test_dac_nids,
3190 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003191 .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
3192 .channel_mode = alc880_test_modes,
3193 .input_mux = &alc880_test_capture_source,
3194 },
3195#endif
3196};
3197
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003198/*
3199 * Automatic parse of I/O pins from the BIOS configuration
3200 */
3201
3202#define NUM_CONTROL_ALLOC 32
3203#define NUM_VERB_ALLOC 32
3204
3205enum {
3206 ALC_CTL_WIDGET_VOL,
3207 ALC_CTL_WIDGET_MUTE,
3208 ALC_CTL_BIND_MUTE,
3209};
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003210static struct snd_kcontrol_new alc880_control_templates[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003211 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
3212 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Takashi Iwai985be542005-11-02 18:26:49 +01003213 HDA_BIND_MUTE(NULL, 0, 0, 0),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003214};
3215
3216/* add dynamic controls */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003217static int add_control(struct alc_spec *spec, int type, const char *name,
3218 unsigned long val)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003219{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003220 struct snd_kcontrol_new *knew;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003221
3222 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
3223 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
3224
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003225 /* array + terminator */
3226 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL);
3227 if (!knew)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003228 return -ENOMEM;
3229 if (spec->kctl_alloc) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003230 memcpy(knew, spec->kctl_alloc,
3231 sizeof(*knew) * spec->num_kctl_alloc);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003232 kfree(spec->kctl_alloc);
3233 }
3234 spec->kctl_alloc = knew;
3235 spec->num_kctl_alloc = num;
3236 }
3237
3238 knew = &spec->kctl_alloc[spec->num_kctl_used];
3239 *knew = alc880_control_templates[type];
Paulo Marques543537b2005-06-23 00:09:02 -07003240 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003241 if (!knew->name)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003242 return -ENOMEM;
3243 knew->private_value = val;
3244 spec->num_kctl_used++;
3245 return 0;
3246}
3247
3248#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
3249#define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
3250#define alc880_is_multi_pin(nid) ((nid) >= 0x18)
3251#define alc880_multi_pin_idx(nid) ((nid) - 0x18)
3252#define alc880_is_input_pin(nid) ((nid) >= 0x18)
3253#define alc880_input_pin_idx(nid) ((nid) - 0x18)
3254#define alc880_idx_to_dac(nid) ((nid) + 0x02)
3255#define alc880_dac_to_idx(nid) ((nid) - 0x02)
3256#define alc880_idx_to_mixer(nid) ((nid) + 0x0c)
3257#define alc880_idx_to_selector(nid) ((nid) + 0x10)
3258#define ALC880_PIN_CD_NID 0x1c
3259
3260/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003261static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
3262 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003263{
3264 hda_nid_t nid;
3265 int assigned[4];
3266 int i, j;
3267
3268 memset(assigned, 0, sizeof(assigned));
Takashi Iwaib0af0de2005-06-21 14:49:19 +02003269 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003270
3271 /* check the pins hardwired to audio widget */
3272 for (i = 0; i < cfg->line_outs; i++) {
3273 nid = cfg->line_out_pins[i];
3274 if (alc880_is_fixed_pin(nid)) {
3275 int idx = alc880_fixed_pin_idx(nid);
Libin Yang5014f192005-11-23 15:48:36 +01003276 spec->multiout.dac_nids[i] = alc880_idx_to_dac(idx);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003277 assigned[idx] = 1;
3278 }
3279 }
3280 /* left pins can be connect to any audio widget */
3281 for (i = 0; i < cfg->line_outs; i++) {
3282 nid = cfg->line_out_pins[i];
3283 if (alc880_is_fixed_pin(nid))
3284 continue;
3285 /* search for an empty channel */
3286 for (j = 0; j < cfg->line_outs; j++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003287 if (!assigned[j]) {
3288 spec->multiout.dac_nids[i] =
3289 alc880_idx_to_dac(j);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003290 assigned[j] = 1;
3291 break;
3292 }
3293 }
3294 }
3295 spec->multiout.num_dacs = cfg->line_outs;
3296 return 0;
3297}
3298
3299/* add playback controls from the parsed DAC table */
Kailang Yangdf694da2005-12-05 19:42:22 +01003300static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
3301 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003302{
3303 char name[32];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003304 static const char *chname[4] = {
3305 "Front", "Surround", NULL /*CLFE*/, "Side"
3306 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003307 hda_nid_t nid;
3308 int i, err;
3309
3310 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003311 if (!spec->multiout.dac_nids[i])
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003312 continue;
3313 nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
3314 if (i == 2) {
3315 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003316 err = add_control(spec, ALC_CTL_WIDGET_VOL,
3317 "Center Playback Volume",
3318 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
3319 HDA_OUTPUT));
3320 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003321 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003322 err = add_control(spec, ALC_CTL_WIDGET_VOL,
3323 "LFE Playback Volume",
3324 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
3325 HDA_OUTPUT));
3326 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003327 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003328 err = add_control(spec, ALC_CTL_BIND_MUTE,
3329 "Center Playback Switch",
3330 HDA_COMPOSE_AMP_VAL(nid, 1, 2,
3331 HDA_INPUT));
3332 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003333 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003334 err = add_control(spec, ALC_CTL_BIND_MUTE,
3335 "LFE Playback Switch",
3336 HDA_COMPOSE_AMP_VAL(nid, 2, 2,
3337 HDA_INPUT));
3338 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003339 return err;
3340 } else {
3341 sprintf(name, "%s Playback Volume", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003342 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
3343 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
3344 HDA_OUTPUT));
3345 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003346 return err;
3347 sprintf(name, "%s Playback Switch", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003348 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
3349 HDA_COMPOSE_AMP_VAL(nid, 3, 2,
3350 HDA_INPUT));
3351 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003352 return err;
3353 }
3354 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003355 return 0;
3356}
3357
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003358/* add playback controls for speaker and HP outputs */
3359static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
3360 const char *pfx)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003361{
3362 hda_nid_t nid;
3363 int err;
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003364 char name[32];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003365
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003366 if (!pin)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003367 return 0;
3368
3369 if (alc880_is_fixed_pin(pin)) {
3370 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
Takashi Iwai82bc9552006-03-21 11:24:42 +01003371 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003372 if (!spec->multiout.hp_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003373 spec->multiout.hp_nid = nid;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003374 else
3375 spec->multiout.extra_out_nid[0] = nid;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003376 /* control HP volume/switch on the output mixer amp */
3377 nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003378 sprintf(name, "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003379 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
3380 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
3381 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003382 return err;
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003383 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003384 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
3385 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
3386 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003387 return err;
3388 } else if (alc880_is_multi_pin(pin)) {
3389 /* set manual connection */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003390 /* we have only a switch on HP-out PIN */
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003391 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003392 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
3393 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
3394 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003395 return err;
3396 }
3397 return 0;
3398}
3399
3400/* create input playback/capture controls for the given pin */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003401static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
3402 const char *ctlname,
Kailang Yangdf694da2005-12-05 19:42:22 +01003403 int idx, hda_nid_t mix_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003404{
3405 char name[32];
Kailang Yangdf694da2005-12-05 19:42:22 +01003406 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003407
3408 sprintf(name, "%s Playback Volume", ctlname);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003409 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
3410 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
3411 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003412 return err;
3413 sprintf(name, "%s Playback Switch", ctlname);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003414 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
3415 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
3416 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003417 return err;
3418 return 0;
3419}
3420
3421/* create playback/capture controls for input pins */
Kailang Yangdf694da2005-12-05 19:42:22 +01003422static int alc880_auto_create_analog_input_ctls(struct alc_spec *spec,
3423 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003424{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003425 struct hda_input_mux *imux = &spec->private_imux;
Kailang Yangdf694da2005-12-05 19:42:22 +01003426 int i, err, idx;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003427
3428 for (i = 0; i < AUTO_PIN_LAST; i++) {
3429 if (alc880_is_input_pin(cfg->input_pins[i])) {
Kailang Yangdf694da2005-12-05 19:42:22 +01003430 idx = alc880_input_pin_idx(cfg->input_pins[i]);
Takashi Iwai4a471b72005-12-07 13:56:29 +01003431 err = new_analog_input(spec, cfg->input_pins[i],
3432 auto_pin_cfg_labels[i],
Kailang Yangdf694da2005-12-05 19:42:22 +01003433 idx, 0x0b);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003434 if (err < 0)
3435 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003436 imux->items[imux->num_items].label =
3437 auto_pin_cfg_labels[i];
3438 imux->items[imux->num_items].index =
3439 alc880_input_pin_idx(cfg->input_pins[i]);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003440 imux->num_items++;
3441 }
3442 }
3443 return 0;
3444}
3445
Kailang Yangdf694da2005-12-05 19:42:22 +01003446static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
3447 hda_nid_t nid, int pin_type,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003448 int dac_idx)
3449{
3450 /* set as output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003451 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
3452 pin_type);
3453 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
3454 AMP_OUT_UNMUTE);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003455 /* need the manual connection? */
3456 if (alc880_is_multi_pin(nid)) {
3457 struct alc_spec *spec = codec->spec;
3458 int idx = alc880_multi_pin_idx(nid);
3459 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
3460 AC_VERB_SET_CONNECT_SEL,
3461 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
3462 }
3463}
3464
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02003465static int get_pin_type(int line_out_type)
3466{
3467 if (line_out_type == AUTO_PIN_HP_OUT)
3468 return PIN_HP;
3469 else
3470 return PIN_OUT;
3471}
3472
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003473static void alc880_auto_init_multi_out(struct hda_codec *codec)
3474{
3475 struct alc_spec *spec = codec->spec;
3476 int i;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003477
3478 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003479 for (i = 0; i < spec->autocfg.line_outs; i++) {
3480 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02003481 int pin_type = get_pin_type(spec->autocfg.line_out_type);
3482 alc880_auto_set_output_and_unmute(codec, nid, pin_type, i);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003483 }
3484}
3485
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003486static void alc880_auto_init_extra_out(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003487{
3488 struct alc_spec *spec = codec->spec;
3489 hda_nid_t pin;
3490
Takashi Iwai82bc9552006-03-21 11:24:42 +01003491 pin = spec->autocfg.speaker_pins[0];
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003492 if (pin) /* connect to front */
3493 alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003494 pin = spec->autocfg.hp_pins[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003495 if (pin) /* connect to front */
3496 alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
3497}
3498
3499static void alc880_auto_init_analog_input(struct hda_codec *codec)
3500{
3501 struct alc_spec *spec = codec->spec;
3502 int i;
3503
3504 for (i = 0; i < AUTO_PIN_LAST; i++) {
3505 hda_nid_t nid = spec->autocfg.input_pins[i];
3506 if (alc880_is_input_pin(nid)) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003507 snd_hda_codec_write(codec, nid, 0,
3508 AC_VERB_SET_PIN_WIDGET_CONTROL,
3509 i <= AUTO_PIN_FRONT_MIC ?
3510 PIN_VREF80 : PIN_IN);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003511 if (nid != ALC880_PIN_CD_NID)
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003512 snd_hda_codec_write(codec, nid, 0,
3513 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003514 AMP_OUT_MUTE);
3515 }
3516 }
3517}
3518
3519/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003520/* return 1 if successful, 0 if the proper config is not found,
3521 * or a negative error code
3522 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003523static int alc880_parse_auto_config(struct hda_codec *codec)
3524{
3525 struct alc_spec *spec = codec->spec;
3526 int err;
Kailang Yangdf694da2005-12-05 19:42:22 +01003527 static hda_nid_t alc880_ignore[] = { 0x1d, 0 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003528
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003529 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
3530 alc880_ignore);
3531 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003532 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003533 if (!spec->autocfg.line_outs)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003534 return 0; /* can't find valid BIOS pin config */
Kailang Yangdf694da2005-12-05 19:42:22 +01003535
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003536 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
3537 if (err < 0)
3538 return err;
3539 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
3540 if (err < 0)
3541 return err;
3542 err = alc880_auto_create_extra_out(spec,
3543 spec->autocfg.speaker_pins[0],
3544 "Speaker");
3545 if (err < 0)
3546 return err;
3547 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
3548 "Headphone");
3549 if (err < 0)
3550 return err;
3551 err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg);
3552 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003553 return err;
3554
3555 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
3556
3557 if (spec->autocfg.dig_out_pin)
3558 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
3559 if (spec->autocfg.dig_in_pin)
3560 spec->dig_in_nid = ALC880_DIGIN_NID;
3561
3562 if (spec->kctl_alloc)
3563 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
3564
3565 spec->init_verbs[spec->num_init_verbs++] = alc880_volume_init_verbs;
3566
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003567 spec->num_mux_defs = 1;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003568 spec->input_mux = &spec->private_imux;
3569
3570 return 1;
3571}
3572
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003573/* additional initialization for auto-configuration model */
3574static void alc880_auto_init(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003575{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003576 alc880_auto_init_multi_out(codec);
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003577 alc880_auto_init_extra_out(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003578 alc880_auto_init_analog_input(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003579}
3580
3581/*
3582 * OK, here we have finally the patch for ALC880
3583 */
3584
Linus Torvalds1da177e2005-04-16 15:20:36 -07003585static int patch_alc880(struct hda_codec *codec)
3586{
3587 struct alc_spec *spec;
3588 int board_config;
Kailang Yangdf694da2005-12-05 19:42:22 +01003589 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003591 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003592 if (spec == NULL)
3593 return -ENOMEM;
3594
3595 codec->spec = spec;
3596
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003597 board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
3598 alc880_models,
3599 alc880_cfg_tbl);
3600 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003601 printk(KERN_INFO "hda_codec: Unknown model for ALC880, "
3602 "trying auto-probe from BIOS...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003603 board_config = ALC880_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003604 }
3605
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003606 if (board_config == ALC880_AUTO) {
3607 /* automatic parse from the BIOS config */
3608 err = alc880_parse_auto_config(codec);
3609 if (err < 0) {
3610 alc_free(codec);
3611 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003612 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003613 printk(KERN_INFO
3614 "hda_codec: Cannot set up configuration "
3615 "from BIOS. Using 3-stack mode...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003616 board_config = ALC880_3ST;
3617 }
3618 }
3619
Kailang Yangdf694da2005-12-05 19:42:22 +01003620 if (board_config != ALC880_AUTO)
3621 setup_preset(spec, &alc880_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003622
3623 spec->stream_name_analog = "ALC880 Analog";
3624 spec->stream_analog_playback = &alc880_pcm_analog_playback;
3625 spec->stream_analog_capture = &alc880_pcm_analog_capture;
3626
3627 spec->stream_name_digital = "ALC880 Digital";
3628 spec->stream_digital_playback = &alc880_pcm_digital_playback;
3629 spec->stream_digital_capture = &alc880_pcm_digital_capture;
3630
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003631 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003632 /* check whether NID 0x07 is valid */
Takashi Iwai54d17402005-11-21 16:33:22 +01003633 unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003634 /* get type */
3635 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003636 if (wcap != AC_WID_AUD_IN) {
3637 spec->adc_nids = alc880_adc_nids_alt;
3638 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003639 spec->mixers[spec->num_mixers] =
3640 alc880_capture_alt_mixer;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003641 spec->num_mixers++;
3642 } else {
3643 spec->adc_nids = alc880_adc_nids;
3644 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
3645 spec->mixers[spec->num_mixers] = alc880_capture_mixer;
3646 spec->num_mixers++;
3647 }
3648 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003649
Takashi Iwai2134ea42008-01-10 16:53:55 +01003650 spec->vmaster_nid = 0x0c;
3651
Linus Torvalds1da177e2005-04-16 15:20:36 -07003652 codec->patch_ops = alc_patch_ops;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003653 if (board_config == ALC880_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003654 spec->init_hook = alc880_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02003655#ifdef CONFIG_SND_HDA_POWER_SAVE
3656 if (!spec->loopback.amplist)
3657 spec->loopback.amplist = alc880_loopbacks;
3658#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07003659
3660 return 0;
3661}
3662
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003663
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664/*
3665 * ALC260 support
3666 */
3667
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003668static hda_nid_t alc260_dac_nids[1] = {
3669 /* front */
3670 0x02,
3671};
3672
3673static hda_nid_t alc260_adc_nids[1] = {
3674 /* ADC0 */
3675 0x04,
3676};
3677
Kailang Yangdf694da2005-12-05 19:42:22 +01003678static hda_nid_t alc260_adc_nids_alt[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003679 /* ADC1 */
3680 0x05,
3681};
3682
Kailang Yangdf694da2005-12-05 19:42:22 +01003683static hda_nid_t alc260_hp_adc_nids[2] = {
3684 /* ADC1, 0 */
3685 0x05, 0x04
3686};
3687
Jonathan Woithed57fdac2006-02-28 11:38:35 +01003688/* NIDs used when simultaneous access to both ADCs makes sense. Note that
3689 * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
3690 */
3691static hda_nid_t alc260_dual_adc_nids[2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003692 /* ADC0, ADC1 */
3693 0x04, 0x05
3694};
3695
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003696#define ALC260_DIGOUT_NID 0x03
3697#define ALC260_DIGIN_NID 0x06
3698
3699static struct hda_input_mux alc260_capture_source = {
3700 .num_items = 4,
3701 .items = {
3702 { "Mic", 0x0 },
3703 { "Front Mic", 0x1 },
3704 { "Line", 0x2 },
3705 { "CD", 0x4 },
3706 },
3707};
3708
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01003709/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003710 * headphone jack and the internal CD lines since these are the only pins at
3711 * which audio can appear. For flexibility, also allow the option of
3712 * recording the mixer output on the second ADC (ADC0 doesn't have a
3713 * connection to the mixer output).
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003714 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003715static struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
3716 {
3717 .num_items = 3,
3718 .items = {
3719 { "Mic/Line", 0x0 },
3720 { "CD", 0x4 },
3721 { "Headphone", 0x2 },
3722 },
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003723 },
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003724 {
3725 .num_items = 4,
3726 .items = {
3727 { "Mic/Line", 0x0 },
3728 { "CD", 0x4 },
3729 { "Headphone", 0x2 },
3730 { "Mixer", 0x5 },
3731 },
3732 },
3733
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003734};
3735
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003736/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
3737 * the Fujitsu S702x, but jacks are marked differently.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01003738 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003739static struct hda_input_mux alc260_acer_capture_sources[2] = {
3740 {
3741 .num_items = 4,
3742 .items = {
3743 { "Mic", 0x0 },
3744 { "Line", 0x2 },
3745 { "CD", 0x4 },
3746 { "Headphone", 0x5 },
3747 },
3748 },
3749 {
3750 .num_items = 5,
3751 .items = {
3752 { "Mic", 0x0 },
3753 { "Line", 0x2 },
3754 { "CD", 0x4 },
3755 { "Headphone", 0x6 },
3756 { "Mixer", 0x5 },
3757 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01003758 },
3759};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003760/*
3761 * This is just place-holder, so there's something for alc_build_pcms to look
3762 * at when it calculates the maximum number of channels. ALC260 has no mixer
3763 * element which allows changing the channel mode, so the verb list is
3764 * never used.
3765 */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01003766static struct hda_channel_mode alc260_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003767 { 2, NULL },
3768};
3769
Kailang Yangdf694da2005-12-05 19:42:22 +01003770
3771/* Mixer combinations
3772 *
3773 * basic: base_output + input + pc_beep + capture
3774 * HP: base_output + input + capture_alt
3775 * HP_3013: hp_3013 + input + capture
3776 * fujitsu: fujitsu + capture
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01003777 * acer: acer + capture
Kailang Yangdf694da2005-12-05 19:42:22 +01003778 */
3779
3780static struct snd_kcontrol_new alc260_base_output_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02003781 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003782 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01003783 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
3784 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
3785 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
3786 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
3787 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003788};
Kailang Yangdf694da2005-12-05 19:42:22 +01003789
3790static struct snd_kcontrol_new alc260_input_mixer[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003791 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
3792 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
3793 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
3794 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
3795 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
3796 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
3797 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
3798 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003799 { } /* end */
3800};
3801
Kailang Yangdf694da2005-12-05 19:42:22 +01003802static struct snd_kcontrol_new alc260_pc_beep_mixer[] = {
3803 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x07, 0x05, HDA_INPUT),
3804 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x07, 0x05, HDA_INPUT),
3805 { } /* end */
3806};
3807
3808static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
3809 HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
3810 HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
3811 HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
3812 HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
3813 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
3814 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
3815 HDA_CODEC_VOLUME_MONO("iSpeaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
3816 HDA_CODEC_MUTE_MONO("iSpeaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003817 { } /* end */
3818};
3819
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003820/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12,
3821 * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10.
3822 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003823static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003824 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003825 HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003826 ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003827 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
3828 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
3829 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
3830 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003831 ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003832 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
3833 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
3834 HDA_CODEC_VOLUME("Internal Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003835 HDA_BIND_MUTE("Internal Speaker Playback Switch", 0x09, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01003836 { } /* end */
3837};
3838
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003839/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current
3840 * versions of the ALC260 don't act on requests to enable mic bias from NID
3841 * 0x0f (used to drive the headphone jack in these laptops). The ALC260
3842 * datasheet doesn't mention this restriction. At this stage it's not clear
3843 * whether this behaviour is intentional or is a hardware bug in chip
3844 * revisions available in early 2006. Therefore for now allow the
3845 * "Headphone Jack Mode" control to span all choices, but if it turns out
3846 * that the lack of mic bias for this NID is intentional we could change the
3847 * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
3848 *
3849 * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
3850 * don't appear to make the mic bias available from the "line" jack, even
3851 * though the NID used for this jack (0x14) can supply it. The theory is
3852 * that perhaps Acer have included blocking capacitors between the ALC260
3853 * and the output jack. If this turns out to be the case for all such
3854 * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
3855 * to ALC_PIN_DIR_INOUT_NOMICBIAS.
Jonathan Woithebd869482006-11-28 11:35:52 +01003856 *
3857 * The C20x Tablet series have a mono internal speaker which is controlled
3858 * via the chip's Mono sum widget and pin complex, so include the necessary
3859 * controls for such models. On models without a "mono speaker" the control
3860 * won't do anything.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003861 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01003862static struct snd_kcontrol_new alc260_acer_mixer[] = {
3863 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
3864 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003865 ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
Jonathan Woithebd869482006-11-28 11:35:52 +01003866 HDA_CODEC_VOLUME_MONO("Mono Speaker Playback Volume", 0x0a, 1, 0x0,
3867 HDA_OUTPUT),
3868 HDA_BIND_MUTE_MONO("Mono Speaker Playback Switch", 0x0a, 1, 2,
3869 HDA_INPUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01003870 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
3871 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
3872 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
3873 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
3874 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
3875 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
3876 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
3877 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
3878 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
3879 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
3880 { } /* end */
3881};
3882
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003883/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
3884 * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17.
3885 */
3886static struct snd_kcontrol_new alc260_will_mixer[] = {
3887 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
3888 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
3889 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
3890 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
3891 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
3892 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
3893 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
3894 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
3895 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
3896 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
3897 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
3898 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
3899 { } /* end */
3900};
3901
3902/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
3903 * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
3904 */
3905static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
3906 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
3907 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
3908 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
3909 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
3910 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
3911 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
3912 HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
3913 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
3914 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
3915 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
3916 { } /* end */
3917};
3918
Kailang Yangdf694da2005-12-05 19:42:22 +01003919/* capture mixer elements */
3920static struct snd_kcontrol_new alc260_capture_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003921 HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT),
3922 HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01003923 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x05, 0x0, HDA_INPUT),
3924 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x05, 0x0, HDA_INPUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003925 {
3926 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Kailang Yangdf694da2005-12-05 19:42:22 +01003927 /* The multiple "Capture Source" controls confuse alsamixer
3928 * So call somewhat different..
3929 * FIXME: the controls appear in the "playback" view!
3930 */
3931 /* .name = "Capture Source", */
3932 .name = "Input Source",
3933 .count = 2,
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003934 .info = alc_mux_enum_info,
3935 .get = alc_mux_enum_get,
3936 .put = alc_mux_enum_put,
3937 },
3938 { } /* end */
3939};
3940
Kailang Yangdf694da2005-12-05 19:42:22 +01003941static struct snd_kcontrol_new alc260_capture_alt_mixer[] = {
3942 HDA_CODEC_VOLUME("Capture Volume", 0x05, 0x0, HDA_INPUT),
3943 HDA_CODEC_MUTE("Capture Switch", 0x05, 0x0, HDA_INPUT),
3944 {
3945 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3946 /* The multiple "Capture Source" controls confuse alsamixer
3947 * So call somewhat different..
3948 * FIXME: the controls appear in the "playback" view!
3949 */
3950 /* .name = "Capture Source", */
3951 .name = "Input Source",
3952 .count = 1,
3953 .info = alc_mux_enum_info,
3954 .get = alc_mux_enum_get,
3955 .put = alc_mux_enum_put,
3956 },
3957 { } /* end */
3958};
3959
3960/*
3961 * initialization verbs
3962 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003963static struct hda_verb alc260_init_verbs[] = {
3964 /* Line In pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02003965 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003966 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02003967 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003968 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02003969 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003970 /* Mic2 (front panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02003971 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003972 /* LINE-2 is used for line-out in rear */
Takashi Iwai05acb862005-06-10 19:50:25 +02003973 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003974 /* select line-out */
Jonathan Woithefd56f2d2006-01-24 10:35:46 +01003975 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003976 /* LINE-OUT pin */
Takashi Iwai05acb862005-06-10 19:50:25 +02003977 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003978 /* enable HP */
Takashi Iwai05acb862005-06-10 19:50:25 +02003979 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003980 /* enable Mono */
Takashi Iwai05acb862005-06-10 19:50:25 +02003981 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3982 /* mute capture amp left and right */
Takashi Iwai16ded522005-06-10 19:58:24 +02003983 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984 /* set connection select to line in (default select for this ADC) */
3985 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai16ded522005-06-10 19:58:24 +02003986 /* mute capture amp left and right */
3987 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3988 /* set connection select to line in (default select for this ADC) */
3989 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai05acb862005-06-10 19:50:25 +02003990 /* set vol=0 Line-Out mixer amp left and right */
3991 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3992 /* unmute pin widget amp left and right (no gain on this amp) */
3993 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3994 /* set vol=0 HP mixer amp left and right */
3995 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3996 /* unmute pin widget amp left and right (no gain on this amp) */
3997 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3998 /* set vol=0 Mono mixer amp left and right */
3999 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4000 /* unmute pin widget amp left and right (no gain on this amp) */
4001 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4002 /* unmute LINE-2 out pin */
4003 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004004 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4005 * Line In 2 = 0x03
4006 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004007 /* mute analog inputs */
4008 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4009 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4010 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4011 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4012 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004013 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004014 /* mute Front out path */
4015 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4016 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4017 /* mute Headphone out path */
4018 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4019 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4020 /* mute Mono out path */
4021 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4022 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004023 { }
4024};
4025
Takashi Iwai474167d2006-05-17 17:17:43 +02004026#if 0 /* should be identical with alc260_init_verbs? */
Kailang Yangdf694da2005-12-05 19:42:22 +01004027static struct hda_verb alc260_hp_init_verbs[] = {
4028 /* Headphone and output */
4029 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
4030 /* mono output */
4031 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4032 /* Mic1 (rear panel) pin widget for input and vref at 80% */
4033 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4034 /* Mic2 (front panel) pin widget for input and vref at 80% */
4035 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4036 /* Line In pin widget for input */
4037 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4038 /* Line-2 pin widget for output */
4039 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4040 /* CD pin widget for input */
4041 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4042 /* unmute amp left and right */
4043 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
4044 /* set connection select to line in (default select for this ADC) */
4045 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
4046 /* unmute Line-Out mixer amp left and right (volume = 0) */
4047 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4048 /* mute pin widget amp left and right (no gain on this amp) */
4049 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
4050 /* unmute HP mixer amp left and right (volume = 0) */
4051 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4052 /* mute pin widget amp left and right (no gain on this amp) */
4053 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004054 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4055 * Line In 2 = 0x03
4056 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004057 /* mute analog inputs */
4058 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4059 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4060 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4061 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4062 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01004063 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
4064 /* Unmute Front out path */
4065 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4066 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4067 /* Unmute Headphone out path */
4068 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4069 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4070 /* Unmute Mono out path */
4071 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4072 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4073 { }
4074};
Takashi Iwai474167d2006-05-17 17:17:43 +02004075#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01004076
4077static struct hda_verb alc260_hp_3013_init_verbs[] = {
4078 /* Line out and output */
4079 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4080 /* mono output */
4081 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4082 /* Mic1 (rear panel) pin widget for input and vref at 80% */
4083 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4084 /* Mic2 (front panel) pin widget for input and vref at 80% */
4085 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4086 /* Line In pin widget for input */
4087 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4088 /* Headphone pin widget for output */
4089 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
4090 /* CD pin widget for input */
4091 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4092 /* unmute amp left and right */
4093 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
4094 /* set connection select to line in (default select for this ADC) */
4095 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
4096 /* unmute Line-Out mixer amp left and right (volume = 0) */
4097 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4098 /* mute pin widget amp left and right (no gain on this amp) */
4099 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
4100 /* unmute HP mixer amp left and right (volume = 0) */
4101 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4102 /* mute pin widget amp left and right (no gain on this amp) */
4103 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004104 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4105 * Line In 2 = 0x03
4106 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004107 /* mute analog inputs */
4108 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4109 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4110 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4111 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4112 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01004113 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
4114 /* Unmute Front out path */
4115 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4116 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4117 /* Unmute Headphone out path */
4118 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4119 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4120 /* Unmute Mono out path */
4121 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4122 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4123 { }
4124};
4125
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004126/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004127 * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
4128 * audio = 0x16, internal speaker = 0x10.
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004129 */
4130static struct hda_verb alc260_fujitsu_init_verbs[] = {
4131 /* Disable all GPIOs */
4132 {0x01, AC_VERB_SET_GPIO_MASK, 0},
4133 /* Internal speaker is connected to headphone pin */
4134 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4135 /* Headphone/Line-out jack connects to Line1 pin; make it an output */
4136 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004137 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
4138 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4139 /* Ensure all other unused pins are disabled and muted. */
4140 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4141 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004142 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004143 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004144 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004145 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4146 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4147 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004148
Jonathan Woithef7ace402006-02-28 11:46:14 +01004149 /* Disable digital (SPDIF) pins */
4150 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
4151 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004152
Jonathan Woithef7ace402006-02-28 11:46:14 +01004153 /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
4154 * when acting as an output.
4155 */
4156 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
4157
4158 /* Start with output sum widgets muted and their output gains at min */
Takashi Iwai8b33a5a2006-02-09 11:57:01 +01004159 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4160 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4161 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4162 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4163 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4164 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4165 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4166 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4167 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004168
Jonathan Woithef7ace402006-02-28 11:46:14 +01004169 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
4170 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4171 /* Unmute Line1 pin widget output buffer since it starts as an output.
4172 * If the pin mode is changed by the user the pin mode control will
4173 * take care of enabling the pin's input/output buffers as needed.
4174 * Therefore there's no need to enable the input buffer at this
4175 * stage.
Jonathan Woithecdcd9262006-02-28 11:36:42 +01004176 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01004177 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithecdcd9262006-02-28 11:36:42 +01004178 /* Unmute input buffer of pin widget used for Line-in (no equiv
4179 * mixer ctrl)
4180 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01004181 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004182
Jonathan Woithef7ace402006-02-28 11:46:14 +01004183 /* Mute capture amp left and right */
4184 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4185 /* Set ADC connection select to match default mixer setting - line
4186 * in (on mic1 pin)
4187 */
4188 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004189
Jonathan Woithef7ace402006-02-28 11:46:14 +01004190 /* Do the same for the second ADC: mute capture input amp and
4191 * set ADC connection to line in (on mic1 pin)
4192 */
4193 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4194 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004195
Jonathan Woithef7ace402006-02-28 11:46:14 +01004196 /* Mute all inputs to mixer widget (even unconnected ones) */
4197 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
4198 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
4199 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
4200 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
4201 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
4202 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
4203 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
4204 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
Takashi Iwai4a471b72005-12-07 13:56:29 +01004205
4206 { }
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004207};
4208
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004209/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
4210 * similar laptops (adapted from Fujitsu init verbs).
4211 */
4212static struct hda_verb alc260_acer_init_verbs[] = {
4213 /* On TravelMate laptops, GPIO 0 enables the internal speaker and
4214 * the headphone jack. Turn this on and rely on the standard mute
4215 * methods whenever the user wants to turn these outputs off.
4216 */
4217 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
4218 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
4219 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
4220 /* Internal speaker/Headphone jack is connected to Line-out pin */
4221 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4222 /* Internal microphone/Mic jack is connected to Mic1 pin */
4223 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
4224 /* Line In jack is connected to Line1 pin */
4225 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Jonathan Woithebd869482006-11-28 11:35:52 +01004226 /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
4227 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004228 /* Ensure all other unused pins are disabled and muted. */
4229 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4230 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004231 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4232 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4233 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4234 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4235 /* Disable digital (SPDIF) pins */
4236 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
4237 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
4238
4239 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
4240 * bus when acting as outputs.
4241 */
4242 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
4243 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
4244
4245 /* Start with output sum widgets muted and their output gains at min */
4246 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4247 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4248 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4249 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4250 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4251 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4252 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4253 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4254 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4255
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004256 /* Unmute Line-out pin widget amp left and right
4257 * (no equiv mixer ctrl)
4258 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004259 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithebd869482006-11-28 11:35:52 +01004260 /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
4261 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004262 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
4263 * inputs. If the pin mode is changed by the user the pin mode control
4264 * will take care of enabling the pin's input/output buffers as needed.
4265 * Therefore there's no need to enable the input buffer at this
4266 * stage.
4267 */
4268 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4269 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4270
4271 /* Mute capture amp left and right */
4272 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4273 /* Set ADC connection select to match default mixer setting - mic
4274 * (on mic1 pin)
4275 */
4276 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
4277
4278 /* Do similar with the second ADC: mute capture input amp and
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004279 * set ADC connection to mic to match ALSA's default state.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004280 */
4281 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004282 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004283
4284 /* Mute all inputs to mixer widget (even unconnected ones) */
4285 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
4286 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
4287 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
4288 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
4289 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
4290 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
4291 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
4292 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
4293
4294 { }
4295};
4296
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004297static struct hda_verb alc260_will_verbs[] = {
4298 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4299 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
4300 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
4301 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
4302 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
4303 {0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
4304 {}
4305};
4306
4307static struct hda_verb alc260_replacer_672v_verbs[] = {
4308 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
4309 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
4310 {0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
4311
4312 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
4313 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
4314 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
4315
4316 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4317 {}
4318};
4319
4320/* toggle speaker-output according to the hp-jack state */
4321static void alc260_replacer_672v_automute(struct hda_codec *codec)
4322{
4323 unsigned int present;
4324
4325 /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
4326 present = snd_hda_codec_read(codec, 0x0f, 0,
4327 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
4328 if (present) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004329 snd_hda_codec_write_cache(codec, 0x01, 0,
4330 AC_VERB_SET_GPIO_DATA, 1);
4331 snd_hda_codec_write_cache(codec, 0x0f, 0,
4332 AC_VERB_SET_PIN_WIDGET_CONTROL,
4333 PIN_HP);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004334 } else {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004335 snd_hda_codec_write_cache(codec, 0x01, 0,
4336 AC_VERB_SET_GPIO_DATA, 0);
4337 snd_hda_codec_write_cache(codec, 0x0f, 0,
4338 AC_VERB_SET_PIN_WIDGET_CONTROL,
4339 PIN_OUT);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004340 }
4341}
4342
4343static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
4344 unsigned int res)
4345{
4346 if ((res >> 26) == ALC880_HP_EVENT)
4347 alc260_replacer_672v_automute(codec);
4348}
4349
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004350/* Test configuration for debugging, modelled after the ALC880 test
4351 * configuration.
4352 */
4353#ifdef CONFIG_SND_DEBUG
4354static hda_nid_t alc260_test_dac_nids[1] = {
4355 0x02,
4356};
4357static hda_nid_t alc260_test_adc_nids[2] = {
4358 0x04, 0x05,
4359};
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004360/* For testing the ALC260, each input MUX needs its own definition since
4361 * the signal assignments are different. This assumes that the first ADC
4362 * is NID 0x04.
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01004363 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004364static struct hda_input_mux alc260_test_capture_sources[2] = {
4365 {
4366 .num_items = 7,
4367 .items = {
4368 { "MIC1 pin", 0x0 },
4369 { "MIC2 pin", 0x1 },
4370 { "LINE1 pin", 0x2 },
4371 { "LINE2 pin", 0x3 },
4372 { "CD pin", 0x4 },
4373 { "LINE-OUT pin", 0x5 },
4374 { "HP-OUT pin", 0x6 },
4375 },
4376 },
4377 {
4378 .num_items = 8,
4379 .items = {
4380 { "MIC1 pin", 0x0 },
4381 { "MIC2 pin", 0x1 },
4382 { "LINE1 pin", 0x2 },
4383 { "LINE2 pin", 0x3 },
4384 { "CD pin", 0x4 },
4385 { "Mixer", 0x5 },
4386 { "LINE-OUT pin", 0x6 },
4387 { "HP-OUT pin", 0x7 },
4388 },
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004389 },
4390};
4391static struct snd_kcontrol_new alc260_test_mixer[] = {
4392 /* Output driver widgets */
4393 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
4394 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
4395 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4396 HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
4397 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4398 HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
4399
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004400 /* Modes for retasking pin widgets
4401 * Note: the ALC260 doesn't seem to act on requests to enable mic
4402 * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't
4403 * mention this restriction. At this stage it's not clear whether
4404 * this behaviour is intentional or is a hardware bug in chip
4405 * revisions available at least up until early 2006. Therefore for
4406 * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
4407 * choices, but if it turns out that the lack of mic bias for these
4408 * NIDs is intentional we could change their modes from
4409 * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
4410 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004411 ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
4412 ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
4413 ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
4414 ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
4415 ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
4416 ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
4417
4418 /* Loopback mixer controls */
4419 HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
4420 HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
4421 HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
4422 HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
4423 HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
4424 HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
4425 HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
4426 HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
4427 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4428 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4429 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4430 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
4431 HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
4432 HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
4433 HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
4434 HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01004435
4436 /* Controls for GPIO pins, assuming they are configured as outputs */
4437 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
4438 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
4439 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
4440 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
4441
Jonathan Woithe92621f12006-02-28 11:47:47 +01004442 /* Switches to allow the digital IO pins to be enabled. The datasheet
4443 * is ambigious as to which NID is which; testing on laptops which
4444 * make this output available should provide clarification.
4445 */
4446 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
4447 ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
4448
Jonathan Woithef8225f62008-01-08 12:16:54 +01004449 /* A switch allowing EAPD to be enabled. Some laptops seem to use
4450 * this output to turn on an external amplifier.
4451 */
4452 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
4453 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
4454
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004455 { } /* end */
4456};
4457static struct hda_verb alc260_test_init_verbs[] = {
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01004458 /* Enable all GPIOs as outputs with an initial value of 0 */
4459 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
4460 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
4461 {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
4462
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004463 /* Enable retasking pins as output, initially without power amp */
4464 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4465 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4466 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4467 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4468 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4469 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4470
Jonathan Woithe92621f12006-02-28 11:47:47 +01004471 /* Disable digital (SPDIF) pins initially, but users can enable
4472 * them via a mixer switch. In the case of SPDIF-out, this initverb
4473 * payload also sets the generation to 0, output to be in "consumer"
4474 * PCM format, copyright asserted, no pre-emphasis and no validity
4475 * control.
4476 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004477 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
4478 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
4479
Jonathan Woithef7ace402006-02-28 11:46:14 +01004480 /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004481 * OUT1 sum bus when acting as an output.
4482 */
4483 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
4484 {0x0c, AC_VERB_SET_CONNECT_SEL, 0},
4485 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
4486 {0x0e, AC_VERB_SET_CONNECT_SEL, 0},
4487
4488 /* Start with output sum widgets muted and their output gains at min */
4489 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4490 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4491 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4492 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4493 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4494 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4495 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4496 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4497 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4498
Jonathan Woithecdcd9262006-02-28 11:36:42 +01004499 /* Unmute retasking pin widget output buffers since the default
4500 * state appears to be output. As the pin mode is changed by the
4501 * user the pin mode control will take care of enabling the pin's
4502 * input/output buffers as needed.
4503 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004504 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4505 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4506 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4507 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4508 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4509 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4510 /* Also unmute the mono-out pin widget */
4511 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4512
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004513 /* Mute capture amp left and right */
4514 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004515 /* Set ADC connection select to match default mixer setting (mic1
4516 * pin)
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004517 */
4518 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
4519
4520 /* Do the same for the second ADC: mute capture input amp and
Jonathan Woithef7ace402006-02-28 11:46:14 +01004521 * set ADC connection to mic1 pin
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004522 */
4523 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4524 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
4525
4526 /* Mute all inputs to mixer widget (even unconnected ones) */
4527 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
4528 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
4529 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
4530 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
4531 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
4532 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
4533 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
4534 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
4535
4536 { }
4537};
4538#endif
4539
Linus Torvalds1da177e2005-04-16 15:20:36 -07004540static struct hda_pcm_stream alc260_pcm_analog_playback = {
4541 .substreams = 1,
4542 .channels_min = 2,
4543 .channels_max = 2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004544};
4545
4546static struct hda_pcm_stream alc260_pcm_analog_capture = {
4547 .substreams = 1,
4548 .channels_min = 2,
4549 .channels_max = 2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004550};
4551
Takashi Iwaia3bcba32005-12-06 19:05:29 +01004552#define alc260_pcm_digital_playback alc880_pcm_digital_playback
4553#define alc260_pcm_digital_capture alc880_pcm_digital_capture
4554
Kailang Yangdf694da2005-12-05 19:42:22 +01004555/*
4556 * for BIOS auto-configuration
4557 */
4558
4559static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
4560 const char *pfx)
4561{
4562 hda_nid_t nid_vol;
4563 unsigned long vol_val, sw_val;
4564 char name[32];
4565 int err;
4566
4567 if (nid >= 0x0f && nid < 0x11) {
4568 nid_vol = nid - 0x7;
4569 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
4570 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
4571 } else if (nid == 0x11) {
4572 nid_vol = nid - 0x7;
4573 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT);
4574 sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
4575 } else if (nid >= 0x12 && nid <= 0x15) {
4576 nid_vol = 0x08;
4577 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
4578 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
4579 } else
4580 return 0; /* N/A */
4581
4582 snprintf(name, sizeof(name), "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004583 err = add_control(spec, ALC_CTL_WIDGET_VOL, name, vol_val);
4584 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01004585 return err;
4586 snprintf(name, sizeof(name), "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004587 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, sw_val);
4588 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01004589 return err;
4590 return 1;
4591}
4592
4593/* add playback controls from the parsed DAC table */
4594static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
4595 const struct auto_pin_cfg *cfg)
4596{
4597 hda_nid_t nid;
4598 int err;
4599
4600 spec->multiout.num_dacs = 1;
4601 spec->multiout.dac_nids = spec->private_dac_nids;
4602 spec->multiout.dac_nids[0] = 0x02;
4603
4604 nid = cfg->line_out_pins[0];
4605 if (nid) {
4606 err = alc260_add_playback_controls(spec, nid, "Front");
4607 if (err < 0)
4608 return err;
4609 }
4610
Takashi Iwai82bc9552006-03-21 11:24:42 +01004611 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01004612 if (nid) {
4613 err = alc260_add_playback_controls(spec, nid, "Speaker");
4614 if (err < 0)
4615 return err;
4616 }
4617
Takashi Iwaieb06ed82006-09-20 17:10:27 +02004618 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01004619 if (nid) {
4620 err = alc260_add_playback_controls(spec, nid, "Headphone");
4621 if (err < 0)
4622 return err;
4623 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004624 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01004625}
4626
4627/* create playback/capture controls for input pins */
4628static int alc260_auto_create_analog_input_ctls(struct alc_spec *spec,
4629 const struct auto_pin_cfg *cfg)
4630{
Kailang Yangdf694da2005-12-05 19:42:22 +01004631 struct hda_input_mux *imux = &spec->private_imux;
4632 int i, err, idx;
4633
4634 for (i = 0; i < AUTO_PIN_LAST; i++) {
4635 if (cfg->input_pins[i] >= 0x12) {
4636 idx = cfg->input_pins[i] - 0x12;
Takashi Iwai4a471b72005-12-07 13:56:29 +01004637 err = new_analog_input(spec, cfg->input_pins[i],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004638 auto_pin_cfg_labels[i], idx,
4639 0x07);
Kailang Yangdf694da2005-12-05 19:42:22 +01004640 if (err < 0)
4641 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004642 imux->items[imux->num_items].label =
4643 auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +01004644 imux->items[imux->num_items].index = idx;
4645 imux->num_items++;
4646 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004647 if (cfg->input_pins[i] >= 0x0f && cfg->input_pins[i] <= 0x10){
Kailang Yangdf694da2005-12-05 19:42:22 +01004648 idx = cfg->input_pins[i] - 0x09;
Takashi Iwai4a471b72005-12-07 13:56:29 +01004649 err = new_analog_input(spec, cfg->input_pins[i],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004650 auto_pin_cfg_labels[i], idx,
4651 0x07);
Kailang Yangdf694da2005-12-05 19:42:22 +01004652 if (err < 0)
4653 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004654 imux->items[imux->num_items].label =
4655 auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +01004656 imux->items[imux->num_items].index = idx;
4657 imux->num_items++;
4658 }
4659 }
4660 return 0;
4661}
4662
4663static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
4664 hda_nid_t nid, int pin_type,
4665 int sel_idx)
4666{
4667 /* set as output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004668 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4669 pin_type);
4670 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
4671 AMP_OUT_UNMUTE);
Kailang Yangdf694da2005-12-05 19:42:22 +01004672 /* need the manual connection? */
4673 if (nid >= 0x12) {
4674 int idx = nid - 0x12;
4675 snd_hda_codec_write(codec, idx + 0x0b, 0,
4676 AC_VERB_SET_CONNECT_SEL, sel_idx);
Kailang Yangdf694da2005-12-05 19:42:22 +01004677 }
4678}
4679
4680static void alc260_auto_init_multi_out(struct hda_codec *codec)
4681{
4682 struct alc_spec *spec = codec->spec;
4683 hda_nid_t nid;
4684
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004685 alc_subsystem_id(codec, 0x10, 0x15, 0x0f);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004686 nid = spec->autocfg.line_out_pins[0];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02004687 if (nid) {
4688 int pin_type = get_pin_type(spec->autocfg.line_out_type);
4689 alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
4690 }
Kailang Yangdf694da2005-12-05 19:42:22 +01004691
Takashi Iwai82bc9552006-03-21 11:24:42 +01004692 nid = spec->autocfg.speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01004693 if (nid)
4694 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
4695
Takashi Iwaieb06ed82006-09-20 17:10:27 +02004696 nid = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01004697 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02004698 alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004699}
Kailang Yangdf694da2005-12-05 19:42:22 +01004700
4701#define ALC260_PIN_CD_NID 0x16
4702static void alc260_auto_init_analog_input(struct hda_codec *codec)
4703{
4704 struct alc_spec *spec = codec->spec;
4705 int i;
4706
4707 for (i = 0; i < AUTO_PIN_LAST; i++) {
4708 hda_nid_t nid = spec->autocfg.input_pins[i];
4709 if (nid >= 0x12) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004710 snd_hda_codec_write(codec, nid, 0,
4711 AC_VERB_SET_PIN_WIDGET_CONTROL,
4712 i <= AUTO_PIN_FRONT_MIC ?
4713 PIN_VREF80 : PIN_IN);
Kailang Yangdf694da2005-12-05 19:42:22 +01004714 if (nid != ALC260_PIN_CD_NID)
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004715 snd_hda_codec_write(codec, nid, 0,
4716 AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangdf694da2005-12-05 19:42:22 +01004717 AMP_OUT_MUTE);
4718 }
4719 }
4720}
4721
4722/*
4723 * generic initialization of ADC, input mixers and output mixers
4724 */
4725static struct hda_verb alc260_volume_init_verbs[] = {
4726 /*
4727 * Unmute ADC0-1 and set the default input to mic-in
4728 */
4729 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
4730 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4731 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
4732 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4733
4734 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
4735 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004736 * Note: PASD motherboards uses the Line In 2 as the input for
4737 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01004738 */
4739 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004740 /* mute analog inputs */
4741 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4742 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4743 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4744 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4745 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01004746
4747 /*
4748 * Set up output mixers (0x08 - 0x0a)
4749 */
4750 /* set vol=0 to output mixers */
4751 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4752 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4753 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4754 /* set up input amps for analog loopback */
4755 /* Amp Indices: DAC = 0, mixer = 1 */
4756 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4757 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4758 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4759 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4760 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4761 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4762
4763 { }
4764};
4765
4766static int alc260_parse_auto_config(struct hda_codec *codec)
4767{
4768 struct alc_spec *spec = codec->spec;
4769 unsigned int wcap;
4770 int err;
4771 static hda_nid_t alc260_ignore[] = { 0x17, 0 };
4772
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004773 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
4774 alc260_ignore);
4775 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01004776 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004777 err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
4778 if (err < 0)
Takashi Iwai4a471b72005-12-07 13:56:29 +01004779 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004780 if (!spec->kctl_alloc)
Kailang Yangdf694da2005-12-05 19:42:22 +01004781 return 0; /* can't find valid BIOS pin config */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004782 err = alc260_auto_create_analog_input_ctls(spec, &spec->autocfg);
4783 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01004784 return err;
4785
4786 spec->multiout.max_channels = 2;
4787
4788 if (spec->autocfg.dig_out_pin)
4789 spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
4790 if (spec->kctl_alloc)
4791 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
4792
4793 spec->init_verbs[spec->num_init_verbs++] = alc260_volume_init_verbs;
4794
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004795 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +01004796 spec->input_mux = &spec->private_imux;
4797
4798 /* check whether NID 0x04 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +01004799 wcap = get_wcaps(codec, 0x04);
Kailang Yangdf694da2005-12-05 19:42:22 +01004800 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */
4801 if (wcap != AC_WID_AUD_IN) {
4802 spec->adc_nids = alc260_adc_nids_alt;
4803 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
4804 spec->mixers[spec->num_mixers] = alc260_capture_alt_mixer;
Kailang Yangdf694da2005-12-05 19:42:22 +01004805 } else {
4806 spec->adc_nids = alc260_adc_nids;
4807 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
4808 spec->mixers[spec->num_mixers] = alc260_capture_mixer;
Kailang Yangdf694da2005-12-05 19:42:22 +01004809 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01004810 spec->num_mixers++;
Kailang Yangdf694da2005-12-05 19:42:22 +01004811
4812 return 1;
4813}
4814
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004815/* additional initialization for auto-configuration model */
4816static void alc260_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01004817{
Kailang Yangdf694da2005-12-05 19:42:22 +01004818 alc260_auto_init_multi_out(codec);
4819 alc260_auto_init_analog_input(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01004820}
4821
Takashi Iwaicb53c622007-08-10 17:21:45 +02004822#ifdef CONFIG_SND_HDA_POWER_SAVE
4823static struct hda_amp_list alc260_loopbacks[] = {
4824 { 0x07, HDA_INPUT, 0 },
4825 { 0x07, HDA_INPUT, 1 },
4826 { 0x07, HDA_INPUT, 2 },
4827 { 0x07, HDA_INPUT, 3 },
4828 { 0x07, HDA_INPUT, 4 },
4829 { } /* end */
4830};
4831#endif
4832
Kailang Yangdf694da2005-12-05 19:42:22 +01004833/*
4834 * ALC260 configurations
4835 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004836static const char *alc260_models[ALC260_MODEL_LAST] = {
4837 [ALC260_BASIC] = "basic",
4838 [ALC260_HP] = "hp",
4839 [ALC260_HP_3013] = "hp-3013",
4840 [ALC260_FUJITSU_S702X] = "fujitsu",
4841 [ALC260_ACER] = "acer",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004842 [ALC260_WILL] = "will",
4843 [ALC260_REPLACER_672V] = "replacer",
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004844#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004845 [ALC260_TEST] = "test",
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004846#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004847 [ALC260_AUTO] = "auto",
4848};
4849
4850static struct snd_pci_quirk alc260_cfg_tbl[] = {
Jonathan Woithebd869482006-11-28 11:35:52 +01004851 SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004852 SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
Takashi Iwai9720b712007-03-13 21:46:23 +01004853 SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
Takashi Iwaia8a5d062007-03-15 15:10:28 +01004854 SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_HP_3013),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004855 SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
4856 SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP),
4857 SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_3013),
4858 SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
4859 SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
4860 SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
4861 SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
4862 SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
4863 SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
4864 SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
4865 SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
4866 SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004867 SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004868 SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
Takashi Iwai16ded522005-06-10 19:58:24 +02004869 {}
4870};
4871
Kailang Yangdf694da2005-12-05 19:42:22 +01004872static struct alc_config_preset alc260_presets[] = {
4873 [ALC260_BASIC] = {
4874 .mixers = { alc260_base_output_mixer,
4875 alc260_input_mixer,
4876 alc260_pc_beep_mixer,
4877 alc260_capture_mixer },
4878 .init_verbs = { alc260_init_verbs },
4879 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
4880 .dac_nids = alc260_dac_nids,
4881 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
4882 .adc_nids = alc260_adc_nids,
4883 .num_channel_mode = ARRAY_SIZE(alc260_modes),
4884 .channel_mode = alc260_modes,
4885 .input_mux = &alc260_capture_source,
4886 },
4887 [ALC260_HP] = {
4888 .mixers = { alc260_base_output_mixer,
4889 alc260_input_mixer,
4890 alc260_capture_alt_mixer },
Takashi Iwai474167d2006-05-17 17:17:43 +02004891 .init_verbs = { alc260_init_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01004892 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
4893 .dac_nids = alc260_dac_nids,
4894 .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
4895 .adc_nids = alc260_hp_adc_nids,
4896 .num_channel_mode = ARRAY_SIZE(alc260_modes),
4897 .channel_mode = alc260_modes,
4898 .input_mux = &alc260_capture_source,
4899 },
4900 [ALC260_HP_3013] = {
4901 .mixers = { alc260_hp_3013_mixer,
4902 alc260_input_mixer,
4903 alc260_capture_alt_mixer },
4904 .init_verbs = { alc260_hp_3013_init_verbs },
4905 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
4906 .dac_nids = alc260_dac_nids,
4907 .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
4908 .adc_nids = alc260_hp_adc_nids,
4909 .num_channel_mode = ARRAY_SIZE(alc260_modes),
4910 .channel_mode = alc260_modes,
4911 .input_mux = &alc260_capture_source,
4912 },
4913 [ALC260_FUJITSU_S702X] = {
4914 .mixers = { alc260_fujitsu_mixer,
4915 alc260_capture_mixer },
4916 .init_verbs = { alc260_fujitsu_init_verbs },
4917 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
4918 .dac_nids = alc260_dac_nids,
Jonathan Woithed57fdac2006-02-28 11:38:35 +01004919 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
4920 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01004921 .num_channel_mode = ARRAY_SIZE(alc260_modes),
4922 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004923 .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
4924 .input_mux = alc260_fujitsu_capture_sources,
Kailang Yangdf694da2005-12-05 19:42:22 +01004925 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004926 [ALC260_ACER] = {
4927 .mixers = { alc260_acer_mixer,
4928 alc260_capture_mixer },
4929 .init_verbs = { alc260_acer_init_verbs },
4930 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
4931 .dac_nids = alc260_dac_nids,
4932 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
4933 .adc_nids = alc260_dual_adc_nids,
4934 .num_channel_mode = ARRAY_SIZE(alc260_modes),
4935 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004936 .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
4937 .input_mux = alc260_acer_capture_sources,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004938 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004939 [ALC260_WILL] = {
4940 .mixers = { alc260_will_mixer,
4941 alc260_capture_mixer },
4942 .init_verbs = { alc260_init_verbs, alc260_will_verbs },
4943 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
4944 .dac_nids = alc260_dac_nids,
4945 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
4946 .adc_nids = alc260_adc_nids,
4947 .dig_out_nid = ALC260_DIGOUT_NID,
4948 .num_channel_mode = ARRAY_SIZE(alc260_modes),
4949 .channel_mode = alc260_modes,
4950 .input_mux = &alc260_capture_source,
4951 },
4952 [ALC260_REPLACER_672V] = {
4953 .mixers = { alc260_replacer_672v_mixer,
4954 alc260_capture_mixer },
4955 .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
4956 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
4957 .dac_nids = alc260_dac_nids,
4958 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
4959 .adc_nids = alc260_adc_nids,
4960 .dig_out_nid = ALC260_DIGOUT_NID,
4961 .num_channel_mode = ARRAY_SIZE(alc260_modes),
4962 .channel_mode = alc260_modes,
4963 .input_mux = &alc260_capture_source,
4964 .unsol_event = alc260_replacer_672v_unsol_event,
4965 .init_hook = alc260_replacer_672v_automute,
4966 },
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004967#ifdef CONFIG_SND_DEBUG
4968 [ALC260_TEST] = {
4969 .mixers = { alc260_test_mixer,
4970 alc260_capture_mixer },
4971 .init_verbs = { alc260_test_init_verbs },
4972 .num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
4973 .dac_nids = alc260_test_dac_nids,
4974 .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
4975 .adc_nids = alc260_test_adc_nids,
4976 .num_channel_mode = ARRAY_SIZE(alc260_modes),
4977 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004978 .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
4979 .input_mux = alc260_test_capture_sources,
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004980 },
4981#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01004982};
4983
Linus Torvalds1da177e2005-04-16 15:20:36 -07004984static int patch_alc260(struct hda_codec *codec)
4985{
4986 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01004987 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004988
Takashi Iwaie560d8d2005-09-09 14:21:46 +02004989 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004990 if (spec == NULL)
4991 return -ENOMEM;
4992
4993 codec->spec = spec;
4994
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004995 board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
4996 alc260_models,
4997 alc260_cfg_tbl);
4998 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004999 snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260, "
5000 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01005001 board_config = ALC260_AUTO;
Takashi Iwai16ded522005-06-10 19:58:24 +02005002 }
5003
Kailang Yangdf694da2005-12-05 19:42:22 +01005004 if (board_config == ALC260_AUTO) {
5005 /* automatic parse from the BIOS config */
5006 err = alc260_parse_auto_config(codec);
5007 if (err < 0) {
5008 alc_free(codec);
5009 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005010 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02005011 printk(KERN_INFO
5012 "hda_codec: Cannot set up configuration "
5013 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01005014 board_config = ALC260_BASIC;
5015 }
Takashi Iwai16ded522005-06-10 19:58:24 +02005016 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005017
Kailang Yangdf694da2005-12-05 19:42:22 +01005018 if (board_config != ALC260_AUTO)
5019 setup_preset(spec, &alc260_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005020
5021 spec->stream_name_analog = "ALC260 Analog";
5022 spec->stream_analog_playback = &alc260_pcm_analog_playback;
5023 spec->stream_analog_capture = &alc260_pcm_analog_capture;
5024
Takashi Iwaia3bcba32005-12-06 19:05:29 +01005025 spec->stream_name_digital = "ALC260 Digital";
5026 spec->stream_digital_playback = &alc260_pcm_digital_playback;
5027 spec->stream_digital_capture = &alc260_pcm_digital_capture;
5028
Takashi Iwai2134ea42008-01-10 16:53:55 +01005029 spec->vmaster_nid = 0x08;
5030
Linus Torvalds1da177e2005-04-16 15:20:36 -07005031 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01005032 if (board_config == ALC260_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005033 spec->init_hook = alc260_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02005034#ifdef CONFIG_SND_HDA_POWER_SAVE
5035 if (!spec->loopback.amplist)
5036 spec->loopback.amplist = alc260_loopbacks;
5037#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005038
5039 return 0;
5040}
5041
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005042
Linus Torvalds1da177e2005-04-16 15:20:36 -07005043/*
5044 * ALC882 support
5045 *
5046 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
5047 * configuration. Each pin widget can choose any input DACs and a mixer.
5048 * Each ADC is connected from a mixer of all inputs. This makes possible
5049 * 6-channel independent captures.
5050 *
5051 * In addition, an independent DAC for the multi-playback (not used in this
5052 * driver yet).
5053 */
Kailang Yangdf694da2005-12-05 19:42:22 +01005054#define ALC882_DIGOUT_NID 0x06
5055#define ALC882_DIGIN_NID 0x0a
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01005057static struct hda_channel_mode alc882_ch_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005058 { 8, NULL }
5059};
5060
5061static hda_nid_t alc882_dac_nids[4] = {
5062 /* front, rear, clfe, rear_surr */
5063 0x02, 0x03, 0x04, 0x05
5064};
5065
Kailang Yangdf694da2005-12-05 19:42:22 +01005066/* identical with ALC880 */
5067#define alc882_adc_nids alc880_adc_nids
5068#define alc882_adc_nids_alt alc880_adc_nids_alt
Linus Torvalds1da177e2005-04-16 15:20:36 -07005069
5070/* input MUX */
5071/* FIXME: should be a matrix-type input source selection */
5072
5073static struct hda_input_mux alc882_capture_source = {
5074 .num_items = 4,
5075 .items = {
5076 { "Mic", 0x0 },
5077 { "Front Mic", 0x1 },
5078 { "Line", 0x2 },
5079 { "CD", 0x4 },
5080 },
5081};
Linus Torvalds1da177e2005-04-16 15:20:36 -07005082#define alc882_mux_enum_info alc_mux_enum_info
5083#define alc882_mux_enum_get alc_mux_enum_get
5084
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005085static int alc882_mux_enum_put(struct snd_kcontrol *kcontrol,
5086 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005087{
5088 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
5089 struct alc_spec *spec = codec->spec;
5090 const struct hda_input_mux *imux = spec->input_mux;
5091 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
5092 static hda_nid_t capture_mixers[3] = { 0x24, 0x23, 0x22 };
5093 hda_nid_t nid = capture_mixers[adc_idx];
5094 unsigned int *cur_val = &spec->cur_mux[adc_idx];
5095 unsigned int i, idx;
5096
5097 idx = ucontrol->value.enumerated.item[0];
5098 if (idx >= imux->num_items)
5099 idx = imux->num_items - 1;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005100 if (*cur_val == idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005101 return 0;
5102 for (i = 0; i < imux->num_items; i++) {
Takashi Iwai47fd8302007-08-10 17:11:07 +02005103 unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
5104 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005105 imux->items[i].index,
Takashi Iwai47fd8302007-08-10 17:11:07 +02005106 HDA_AMP_MUTE, v);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005107 }
5108 *cur_val = idx;
5109 return 1;
5110}
5111
Kailang Yangdf694da2005-12-05 19:42:22 +01005112/*
Kailang Yang272a5272007-05-14 11:00:38 +02005113 * 2ch mode
5114 */
5115static struct hda_verb alc882_3ST_ch2_init[] = {
5116 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
5117 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
5118 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
5119 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
5120 { } /* end */
5121};
5122
5123/*
5124 * 6ch mode
5125 */
5126static struct hda_verb alc882_3ST_ch6_init[] = {
5127 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5128 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
5129 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
5130 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5131 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
5132 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
5133 { } /* end */
5134};
5135
5136static struct hda_channel_mode alc882_3ST_6ch_modes[2] = {
5137 { 2, alc882_3ST_ch2_init },
5138 { 6, alc882_3ST_ch6_init },
5139};
5140
5141/*
Kailang Yangdf694da2005-12-05 19:42:22 +01005142 * 6ch mode
5143 */
5144static struct hda_verb alc882_sixstack_ch6_init[] = {
5145 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
5146 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5147 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5148 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5149 { } /* end */
5150};
5151
5152/*
5153 * 8ch mode
5154 */
5155static struct hda_verb alc882_sixstack_ch8_init[] = {
5156 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5157 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5158 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5159 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5160 { } /* end */
5161};
5162
5163static struct hda_channel_mode alc882_sixstack_modes[2] = {
5164 { 6, alc882_sixstack_ch6_init },
5165 { 8, alc882_sixstack_ch8_init },
5166};
5167
Takashi Iwai87350ad2007-08-16 18:19:38 +02005168/*
5169 * macbook pro ALC885 can switch LineIn to LineOut without loosing Mic
5170 */
5171
5172/*
5173 * 2ch mode
5174 */
5175static struct hda_verb alc885_mbp_ch2_init[] = {
5176 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
5177 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5178 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5179 { } /* end */
5180};
5181
5182/*
5183 * 6ch mode
5184 */
5185static struct hda_verb alc885_mbp_ch6_init[] = {
5186 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5187 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5188 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
5189 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5190 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5191 { } /* end */
5192};
5193
5194static struct hda_channel_mode alc885_mbp_6ch_modes[2] = {
5195 { 2, alc885_mbp_ch2_init },
5196 { 6, alc885_mbp_ch6_init },
5197};
5198
5199
Linus Torvalds1da177e2005-04-16 15:20:36 -07005200/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
5201 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
5202 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01005203static struct snd_kcontrol_new alc882_base_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02005204 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005205 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005206 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005207 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005208 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
5209 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005210 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
5211 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005212 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005213 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005214 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
5215 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5216 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5217 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5218 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5219 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01005220 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005221 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5222 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01005223 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005224 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
5225 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5226 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005227 { } /* end */
5228};
5229
Takashi Iwai87350ad2007-08-16 18:19:38 +02005230static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01005231 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
5232 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
5233 HDA_CODEC_MUTE ("Speaker Playback Switch", 0x14, 0x00, HDA_OUTPUT),
5234 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
5235 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5236 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02005237 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
5238 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01005239 HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02005240 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
5241 { } /* end */
5242};
Kailang Yangbdd148a2007-05-08 15:19:08 +02005243static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
5244 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5245 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5246 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5247 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5248 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5249 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5250 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5251 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
5252 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5253 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5254 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
5255 { } /* end */
5256};
5257
Kailang Yang272a5272007-05-14 11:00:38 +02005258static struct snd_kcontrol_new alc882_targa_mixer[] = {
5259 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5260 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5261 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
5262 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5263 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5264 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5265 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5266 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5267 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02005268 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005269 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
5270 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02005271 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005272 { } /* end */
5273};
5274
5275/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
5276 * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
5277 */
5278static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
5279 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5280 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
5281 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
5282 HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT),
5283 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5284 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5285 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5286 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5287 HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
5288 HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
5289 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5290 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02005291 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005292 { } /* end */
5293};
5294
Takashi Iwai914759b2007-09-06 14:52:04 +02005295static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
5296 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5297 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5298 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
5299 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5300 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5301 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5302 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5303 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5304 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
5305 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5306 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5307 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
5308 { } /* end */
5309};
5310
Kailang Yangdf694da2005-12-05 19:42:22 +01005311static struct snd_kcontrol_new alc882_chmode_mixer[] = {
5312 {
5313 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5314 .name = "Channel Mode",
5315 .info = alc_ch_mode_info,
5316 .get = alc_ch_mode_get,
5317 .put = alc_ch_mode_put,
5318 },
5319 { } /* end */
5320};
5321
Linus Torvalds1da177e2005-04-16 15:20:36 -07005322static struct hda_verb alc882_init_verbs[] = {
5323 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005324 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5325 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5326 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005327 /* Rear mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005328 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5329 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5330 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005331 /* CLFE mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005332 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5333 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5334 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005335 /* Side mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005336 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5337 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5338 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005339
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005340 /* Front Pin: output 0 (0x0c) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005341 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005342 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005343 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005344 /* Rear Pin: output 1 (0x0d) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005345 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005346 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005347 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005348 /* CLFE Pin: output 2 (0x0e) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005349 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005350 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005351 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005352 /* Side Pin: output 3 (0x0f) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005353 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005354 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005355 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005356 /* Mic (rear) pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005357 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005358 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5359 /* Front Mic pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005360 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005361 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5362 /* Line In pin: input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005363 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005364 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5365 /* Line-2 In: Headphone output (output 0 - 0x0c) */
5366 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5367 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5368 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005369 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005370 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005371
5372 /* FIXME: use matrix-type input source selection */
5373 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
5374 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Takashi Iwai05acb862005-06-10 19:50:25 +02005375 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5376 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5377 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5378 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005379 /* Input mixer2 */
Takashi Iwai05acb862005-06-10 19:50:25 +02005380 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5381 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5382 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5383 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005384 /* Input mixer3 */
Takashi Iwai05acb862005-06-10 19:50:25 +02005385 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5386 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5387 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5388 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5389 /* ADC1: mute amp left and right */
5390 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005391 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02005392 /* ADC2: mute amp left and right */
5393 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005394 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02005395 /* ADC3: mute amp left and right */
5396 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005397 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005398
5399 { }
5400};
5401
Takashi Iwai4b146cb2006-07-28 14:42:36 +02005402static struct hda_verb alc882_eapd_verbs[] = {
5403 /* change to EAPD mode */
5404 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01005405 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005406 { }
Takashi Iwai4b146cb2006-07-28 14:42:36 +02005407};
5408
Tobin Davis9102cd12006-12-15 10:02:12 +01005409/* Mac Pro test */
5410static struct snd_kcontrol_new alc882_macpro_mixer[] = {
5411 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5412 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5413 HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
5414 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
5415 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
5416 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x02, HDA_INPUT),
5417 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x02, HDA_INPUT),
5418 { } /* end */
5419};
5420
5421static struct hda_verb alc882_macpro_init_verbs[] = {
5422 /* Front mixer: unmute input/output amp left and right (volume = 0) */
5423 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5424 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5425 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5426 /* Front Pin: output 0 (0x0c) */
5427 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5428 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5429 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
5430 /* Front Mic pin: input vref at 80% */
5431 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5432 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5433 /* Speaker: output */
5434 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5435 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5436 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
5437 /* Headphone output (output 0 - 0x0c) */
5438 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5439 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5440 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
5441
5442 /* FIXME: use matrix-type input source selection */
5443 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
5444 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
5445 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5446 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5447 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5448 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5449 /* Input mixer2 */
5450 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5451 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5452 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5453 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5454 /* Input mixer3 */
5455 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5456 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5457 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5458 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5459 /* ADC1: mute amp left and right */
5460 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5461 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
5462 /* ADC2: mute amp left and right */
5463 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5464 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
5465 /* ADC3: mute amp left and right */
5466 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5467 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
5468
5469 { }
5470};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005471
Takashi Iwai87350ad2007-08-16 18:19:38 +02005472/* Macbook Pro rev3 */
5473static struct hda_verb alc885_mbp3_init_verbs[] = {
5474 /* Front mixer: unmute input/output amp left and right (volume = 0) */
5475 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5476 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5477 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5478 /* Rear mixer */
5479 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5480 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5481 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5482 /* Front Pin: output 0 (0x0c) */
5483 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5484 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5485 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
5486 /* HP Pin: output 0 (0x0d) */
5487 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
5488 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5489 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
5490 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
5491 /* Mic (rear) pin: input vref at 80% */
5492 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5493 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5494 /* Front Mic pin: input vref at 80% */
5495 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5496 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5497 /* Line In pin: use output 1 when in LineOut mode */
5498 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
5499 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5500 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
5501
5502 /* FIXME: use matrix-type input source selection */
5503 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
5504 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
5505 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5506 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5507 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5508 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5509 /* Input mixer2 */
5510 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5511 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5512 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5513 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5514 /* Input mixer3 */
5515 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5516 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5517 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5518 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5519 /* ADC1: mute amp left and right */
5520 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5521 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
5522 /* ADC2: mute amp left and right */
5523 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5524 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
5525 /* ADC3: mute amp left and right */
5526 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5527 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
5528
5529 { }
5530};
5531
Nicola Fagnanic54728d2007-07-19 23:28:52 +02005532/* iMac 24 mixer. */
5533static struct snd_kcontrol_new alc885_imac24_mixer[] = {
5534 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
5535 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
5536 { } /* end */
5537};
5538
5539/* iMac 24 init verbs. */
5540static struct hda_verb alc885_imac24_init_verbs[] = {
5541 /* Internal speakers: output 0 (0x0c) */
5542 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5543 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5544 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
5545 /* Internal speakers: output 0 (0x0c) */
5546 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5547 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5548 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
5549 /* Headphone: output 0 (0x0c) */
5550 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5551 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5552 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
5553 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
5554 /* Front Mic: input vref at 80% */
5555 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5556 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5557 { }
5558};
5559
5560/* Toggle speaker-output according to the hp-jack state */
5561static void alc885_imac24_automute(struct hda_codec *codec)
5562{
5563 unsigned int present;
5564
5565 present = snd_hda_codec_read(codec, 0x14, 0,
5566 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02005567 snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0,
5568 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
5569 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
5570 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Nicola Fagnanic54728d2007-07-19 23:28:52 +02005571}
5572
5573/* Processes unsolicited events. */
5574static void alc885_imac24_unsol_event(struct hda_codec *codec,
5575 unsigned int res)
5576{
5577 /* Headphone insertion or removal. */
5578 if ((res >> 26) == ALC880_HP_EVENT)
5579 alc885_imac24_automute(codec);
5580}
5581
Takashi Iwai87350ad2007-08-16 18:19:38 +02005582static void alc885_mbp3_automute(struct hda_codec *codec)
5583{
5584 unsigned int present;
5585
5586 present = snd_hda_codec_read(codec, 0x15, 0,
5587 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
5588 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
5589 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
5590 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
5591 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
5592
5593}
5594static void alc885_mbp3_unsol_event(struct hda_codec *codec,
5595 unsigned int res)
5596{
5597 /* Headphone insertion or removal. */
5598 if ((res >> 26) == ALC880_HP_EVENT)
5599 alc885_mbp3_automute(codec);
5600}
5601
5602
Kailang Yang272a5272007-05-14 11:00:38 +02005603static struct hda_verb alc882_targa_verbs[] = {
5604 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5605 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5606
5607 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5608 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5609
5610 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
5611 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
5612 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
5613
5614 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
5615 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
5616 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
5617 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
5618 { } /* end */
5619};
5620
5621/* toggle speaker-output according to the hp-jack state */
5622static void alc882_targa_automute(struct hda_codec *codec)
5623{
5624 unsigned int present;
5625
5626 present = snd_hda_codec_read(codec, 0x14, 0,
5627 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02005628 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
5629 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005630 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
5631 present ? 1 : 3);
Kailang Yang272a5272007-05-14 11:00:38 +02005632}
5633
5634static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
5635{
5636 /* Looks like the unsol event is incompatible with the standard
5637 * definition. 4bit tag is placed at 26 bit!
5638 */
5639 if (((res >> 26) == ALC880_HP_EVENT)) {
5640 alc882_targa_automute(codec);
5641 }
5642}
5643
5644static struct hda_verb alc882_asus_a7j_verbs[] = {
5645 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5646 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5647
5648 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5649 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5650 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5651
5652 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
5653 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
5654 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
5655
5656 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
5657 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
5658 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
5659 { } /* end */
5660};
5661
Takashi Iwai914759b2007-09-06 14:52:04 +02005662static struct hda_verb alc882_asus_a7m_verbs[] = {
5663 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5664 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5665
5666 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5667 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5668 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5669
5670 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
5671 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
5672 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
5673
5674 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
5675 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
5676 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
5677 { } /* end */
5678};
5679
Tobin Davis9102cd12006-12-15 10:02:12 +01005680static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
5681{
5682 unsigned int gpiostate, gpiomask, gpiodir;
5683
5684 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
5685 AC_VERB_GET_GPIO_DATA, 0);
5686
5687 if (!muted)
5688 gpiostate |= (1 << pin);
5689 else
5690 gpiostate &= ~(1 << pin);
5691
5692 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
5693 AC_VERB_GET_GPIO_MASK, 0);
5694 gpiomask |= (1 << pin);
5695
5696 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
5697 AC_VERB_GET_GPIO_DIRECTION, 0);
5698 gpiodir |= (1 << pin);
5699
5700
5701 snd_hda_codec_write(codec, codec->afg, 0,
5702 AC_VERB_SET_GPIO_MASK, gpiomask);
5703 snd_hda_codec_write(codec, codec->afg, 0,
5704 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
5705
5706 msleep(1);
5707
5708 snd_hda_codec_write(codec, codec->afg, 0,
5709 AC_VERB_SET_GPIO_DATA, gpiostate);
5710}
5711
Takashi Iwai7debbe52007-08-16 15:01:03 +02005712/* set up GPIO at initialization */
5713static void alc885_macpro_init_hook(struct hda_codec *codec)
5714{
5715 alc882_gpio_mute(codec, 0, 0);
5716 alc882_gpio_mute(codec, 1, 0);
5717}
5718
5719/* set up GPIO and update auto-muting at initialization */
5720static void alc885_imac24_init_hook(struct hda_codec *codec)
5721{
5722 alc885_macpro_init_hook(codec);
5723 alc885_imac24_automute(codec);
5724}
5725
Kailang Yangdf694da2005-12-05 19:42:22 +01005726/*
5727 * generic initialization of ADC, input mixers and output mixers
5728 */
5729static struct hda_verb alc882_auto_init_verbs[] = {
5730 /*
5731 * Unmute ADC0-2 and set the default input to mic-in
5732 */
5733 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
5734 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5735 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
5736 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5737 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
5738 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5739
Takashi Iwaicb53c622007-08-10 17:21:45 +02005740 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01005741 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005742 * Note: PASD motherboards uses the Line In 2 as the input for
5743 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01005744 */
5745 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005746 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5747 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5748 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5749 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5750 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01005751
5752 /*
5753 * Set up output mixers (0x0c - 0x0f)
5754 */
5755 /* set vol=0 to output mixers */
5756 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5757 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5758 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5759 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5760 /* set up input amps for analog loopback */
5761 /* Amp Indices: DAC = 0, mixer = 1 */
5762 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5763 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5764 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5765 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5766 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5767 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5768 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5769 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5770 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5771 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5772
5773 /* FIXME: use matrix-type input source selection */
5774 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
5775 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
5776 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5777 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
5778 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
5779 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
5780 /* Input mixer2 */
5781 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5782 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
5783 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
5784 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
5785 /* Input mixer3 */
5786 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5787 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
5788 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
5789 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
5790
5791 { }
5792};
5793
5794/* capture mixer elements */
5795static struct snd_kcontrol_new alc882_capture_alt_mixer[] = {
5796 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
5797 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
5798 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
5799 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
5800 {
5801 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5802 /* The multiple "Capture Source" controls confuse alsamixer
5803 * So call somewhat different..
5804 * FIXME: the controls appear in the "playback" view!
5805 */
5806 /* .name = "Capture Source", */
5807 .name = "Input Source",
5808 .count = 2,
5809 .info = alc882_mux_enum_info,
5810 .get = alc882_mux_enum_get,
5811 .put = alc882_mux_enum_put,
5812 },
5813 { } /* end */
5814};
5815
5816static struct snd_kcontrol_new alc882_capture_mixer[] = {
5817 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
5818 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
5819 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
5820 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
5821 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
5822 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
5823 {
5824 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5825 /* The multiple "Capture Source" controls confuse alsamixer
5826 * So call somewhat different..
5827 * FIXME: the controls appear in the "playback" view!
5828 */
5829 /* .name = "Capture Source", */
5830 .name = "Input Source",
5831 .count = 3,
5832 .info = alc882_mux_enum_info,
5833 .get = alc882_mux_enum_get,
5834 .put = alc882_mux_enum_put,
5835 },
5836 { } /* end */
5837};
5838
Takashi Iwaicb53c622007-08-10 17:21:45 +02005839#ifdef CONFIG_SND_HDA_POWER_SAVE
5840#define alc882_loopbacks alc880_loopbacks
5841#endif
5842
Kailang Yangdf694da2005-12-05 19:42:22 +01005843/* pcm configuration: identiacal with ALC880 */
5844#define alc882_pcm_analog_playback alc880_pcm_analog_playback
5845#define alc882_pcm_analog_capture alc880_pcm_analog_capture
5846#define alc882_pcm_digital_playback alc880_pcm_digital_playback
5847#define alc882_pcm_digital_capture alc880_pcm_digital_capture
5848
5849/*
5850 * configuration and preset
5851 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005852static const char *alc882_models[ALC882_MODEL_LAST] = {
5853 [ALC882_3ST_DIG] = "3stack-dig",
5854 [ALC882_6ST_DIG] = "6stack-dig",
5855 [ALC882_ARIMA] = "arima",
Kailang Yangbdd148a2007-05-08 15:19:08 +02005856 [ALC882_W2JC] = "w2jc",
Takashi Iwai0438a002007-09-06 14:54:11 +02005857 [ALC882_TARGA] = "targa",
5858 [ALC882_ASUS_A7J] = "asus-a7j",
5859 [ALC882_ASUS_A7M] = "asus-a7m",
Tobin Davis9102cd12006-12-15 10:02:12 +01005860 [ALC885_MACPRO] = "macpro",
Takashi Iwai87350ad2007-08-16 18:19:38 +02005861 [ALC885_MBP3] = "mbp3",
Nicola Fagnanic54728d2007-07-19 23:28:52 +02005862 [ALC885_IMAC24] = "imac24",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005863 [ALC882_AUTO] = "auto",
5864};
5865
5866static struct snd_pci_quirk alc882_cfg_tbl[] = {
5867 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
Kailang Yang272a5272007-05-14 11:00:38 +02005868 SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
Kailang Yangac8842a2007-09-20 12:51:39 +02005869 SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
Takashi Iwai914759b2007-09-06 14:52:04 +02005870 SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01005871 SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
Claudio Matsuokac5d9f1c2007-07-19 23:18:32 +02005872 SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
Tobin Davis7b9470d2006-12-28 13:56:48 +01005873 SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01005874 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
5875 SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
5876 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
5877 SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA),
Kailang Yangdf694da2005-12-05 19:42:22 +01005878 {}
5879};
5880
5881static struct alc_config_preset alc882_presets[] = {
5882 [ALC882_3ST_DIG] = {
5883 .mixers = { alc882_base_mixer },
5884 .init_verbs = { alc882_init_verbs },
5885 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
5886 .dac_nids = alc882_dac_nids,
5887 .dig_out_nid = ALC882_DIGOUT_NID,
Kailang Yangdf694da2005-12-05 19:42:22 +01005888 .dig_in_nid = ALC882_DIGIN_NID,
5889 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
5890 .channel_mode = alc882_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02005891 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01005892 .input_mux = &alc882_capture_source,
5893 },
5894 [ALC882_6ST_DIG] = {
5895 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
5896 .init_verbs = { alc882_init_verbs },
5897 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
5898 .dac_nids = alc882_dac_nids,
5899 .dig_out_nid = ALC882_DIGOUT_NID,
Kailang Yangdf694da2005-12-05 19:42:22 +01005900 .dig_in_nid = ALC882_DIGIN_NID,
5901 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
5902 .channel_mode = alc882_sixstack_modes,
5903 .input_mux = &alc882_capture_source,
5904 },
Takashi Iwai4b146cb2006-07-28 14:42:36 +02005905 [ALC882_ARIMA] = {
5906 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
5907 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs },
5908 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
5909 .dac_nids = alc882_dac_nids,
5910 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
5911 .channel_mode = alc882_sixstack_modes,
5912 .input_mux = &alc882_capture_source,
5913 },
Kailang Yangbdd148a2007-05-08 15:19:08 +02005914 [ALC882_W2JC] = {
5915 .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
5916 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
5917 alc880_gpio1_init_verbs },
5918 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
5919 .dac_nids = alc882_dac_nids,
5920 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
5921 .channel_mode = alc880_threestack_modes,
5922 .need_dac_fix = 1,
5923 .input_mux = &alc882_capture_source,
5924 .dig_out_nid = ALC882_DIGOUT_NID,
5925 },
Takashi Iwai87350ad2007-08-16 18:19:38 +02005926 [ALC885_MBP3] = {
5927 .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
5928 .init_verbs = { alc885_mbp3_init_verbs,
5929 alc880_gpio1_init_verbs },
5930 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
5931 .dac_nids = alc882_dac_nids,
5932 .channel_mode = alc885_mbp_6ch_modes,
5933 .num_channel_mode = ARRAY_SIZE(alc885_mbp_6ch_modes),
5934 .input_mux = &alc882_capture_source,
5935 .dig_out_nid = ALC882_DIGOUT_NID,
5936 .dig_in_nid = ALC882_DIGIN_NID,
5937 .unsol_event = alc885_mbp3_unsol_event,
5938 .init_hook = alc885_mbp3_automute,
5939 },
Tobin Davis9102cd12006-12-15 10:02:12 +01005940 [ALC885_MACPRO] = {
5941 .mixers = { alc882_macpro_mixer },
5942 .init_verbs = { alc882_macpro_init_verbs },
5943 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
5944 .dac_nids = alc882_dac_nids,
5945 .dig_out_nid = ALC882_DIGOUT_NID,
5946 .dig_in_nid = ALC882_DIGIN_NID,
5947 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
5948 .channel_mode = alc882_ch_modes,
5949 .input_mux = &alc882_capture_source,
Takashi Iwai7debbe52007-08-16 15:01:03 +02005950 .init_hook = alc885_macpro_init_hook,
Tobin Davis9102cd12006-12-15 10:02:12 +01005951 },
Nicola Fagnanic54728d2007-07-19 23:28:52 +02005952 [ALC885_IMAC24] = {
5953 .mixers = { alc885_imac24_mixer },
5954 .init_verbs = { alc885_imac24_init_verbs },
5955 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
5956 .dac_nids = alc882_dac_nids,
5957 .dig_out_nid = ALC882_DIGOUT_NID,
5958 .dig_in_nid = ALC882_DIGIN_NID,
5959 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
5960 .channel_mode = alc882_ch_modes,
5961 .input_mux = &alc882_capture_source,
5962 .unsol_event = alc885_imac24_unsol_event,
Takashi Iwai7debbe52007-08-16 15:01:03 +02005963 .init_hook = alc885_imac24_init_hook,
Nicola Fagnanic54728d2007-07-19 23:28:52 +02005964 },
Kailang Yang272a5272007-05-14 11:00:38 +02005965 [ALC882_TARGA] = {
5966 .mixers = { alc882_targa_mixer, alc882_chmode_mixer,
5967 alc882_capture_mixer },
5968 .init_verbs = { alc882_init_verbs, alc882_targa_verbs},
5969 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
5970 .dac_nids = alc882_dac_nids,
5971 .dig_out_nid = ALC882_DIGOUT_NID,
5972 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
5973 .adc_nids = alc882_adc_nids,
5974 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
5975 .channel_mode = alc882_3ST_6ch_modes,
5976 .need_dac_fix = 1,
5977 .input_mux = &alc882_capture_source,
5978 .unsol_event = alc882_targa_unsol_event,
5979 .init_hook = alc882_targa_automute,
5980 },
5981 [ALC882_ASUS_A7J] = {
5982 .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer,
5983 alc882_capture_mixer },
5984 .init_verbs = { alc882_init_verbs, alc882_asus_a7j_verbs},
5985 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
5986 .dac_nids = alc882_dac_nids,
5987 .dig_out_nid = ALC882_DIGOUT_NID,
5988 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
5989 .adc_nids = alc882_adc_nids,
5990 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
5991 .channel_mode = alc882_3ST_6ch_modes,
5992 .need_dac_fix = 1,
5993 .input_mux = &alc882_capture_source,
5994 },
Takashi Iwai914759b2007-09-06 14:52:04 +02005995 [ALC882_ASUS_A7M] = {
5996 .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
5997 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
5998 alc880_gpio1_init_verbs,
5999 alc882_asus_a7m_verbs },
6000 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6001 .dac_nids = alc882_dac_nids,
6002 .dig_out_nid = ALC882_DIGOUT_NID,
6003 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
6004 .channel_mode = alc880_threestack_modes,
6005 .need_dac_fix = 1,
6006 .input_mux = &alc882_capture_source,
6007 },
Kailang Yangdf694da2005-12-05 19:42:22 +01006008};
6009
6010
6011/*
Takashi Iwaif95474e2007-07-10 00:47:43 +02006012 * Pin config fixes
6013 */
6014enum {
6015 PINFIX_ABIT_AW9D_MAX
6016};
6017
6018static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
6019 { 0x15, 0x01080104 }, /* side */
6020 { 0x16, 0x01011012 }, /* rear */
6021 { 0x17, 0x01016011 }, /* clfe */
6022 { }
6023};
6024
6025static const struct alc_pincfg *alc882_pin_fixes[] = {
6026 [PINFIX_ABIT_AW9D_MAX] = alc882_abit_aw9d_pinfix,
6027};
6028
6029static struct snd_pci_quirk alc882_pinfix_tbl[] = {
6030 SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
6031 {}
6032};
6033
6034/*
Kailang Yangdf694da2005-12-05 19:42:22 +01006035 * BIOS auto configuration
6036 */
6037static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
6038 hda_nid_t nid, int pin_type,
6039 int dac_idx)
6040{
6041 /* set as output */
6042 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006043 int idx;
6044
Kailang Yangdf694da2005-12-05 19:42:22 +01006045 if (spec->multiout.dac_nids[dac_idx] == 0x25)
6046 idx = 4;
6047 else
6048 idx = spec->multiout.dac_nids[dac_idx] - 2;
6049
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006050 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
6051 pin_type);
6052 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
6053 AMP_OUT_UNMUTE);
Kailang Yangdf694da2005-12-05 19:42:22 +01006054 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
6055
6056}
6057
6058static void alc882_auto_init_multi_out(struct hda_codec *codec)
6059{
6060 struct alc_spec *spec = codec->spec;
6061 int i;
6062
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006063 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Kailang Yangdf694da2005-12-05 19:42:22 +01006064 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006065 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006066 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01006067 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006068 alc882_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006069 i);
Kailang Yangdf694da2005-12-05 19:42:22 +01006070 }
6071}
6072
6073static void alc882_auto_init_hp_out(struct hda_codec *codec)
6074{
6075 struct alc_spec *spec = codec->spec;
6076 hda_nid_t pin;
6077
Takashi Iwaieb06ed82006-09-20 17:10:27 +02006078 pin = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006079 if (pin) /* connect to front */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006080 /* use dac 0 */
6081 alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +01006082}
6083
6084#define alc882_is_input_pin(nid) alc880_is_input_pin(nid)
6085#define ALC882_PIN_CD_NID ALC880_PIN_CD_NID
6086
6087static void alc882_auto_init_analog_input(struct hda_codec *codec)
6088{
6089 struct alc_spec *spec = codec->spec;
6090 int i;
6091
6092 for (i = 0; i < AUTO_PIN_LAST; i++) {
6093 hda_nid_t nid = spec->autocfg.input_pins[i];
6094 if (alc882_is_input_pin(nid)) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006095 snd_hda_codec_write(codec, nid, 0,
6096 AC_VERB_SET_PIN_WIDGET_CONTROL,
6097 i <= AUTO_PIN_FRONT_MIC ?
6098 PIN_VREF80 : PIN_IN);
Kailang Yangdf694da2005-12-05 19:42:22 +01006099 if (nid != ALC882_PIN_CD_NID)
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006100 snd_hda_codec_write(codec, nid, 0,
6101 AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangdf694da2005-12-05 19:42:22 +01006102 AMP_OUT_MUTE);
6103 }
6104 }
6105}
6106
Takashi Iwai776e1842007-08-29 15:07:11 +02006107/* add mic boosts if needed */
6108static int alc_auto_add_mic_boost(struct hda_codec *codec)
6109{
6110 struct alc_spec *spec = codec->spec;
6111 int err;
6112 hda_nid_t nid;
6113
6114 nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
Takashi Iwaice22e032008-01-11 17:38:35 +01006115 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
Takashi Iwai776e1842007-08-29 15:07:11 +02006116 err = add_control(spec, ALC_CTL_WIDGET_VOL,
6117 "Mic Boost",
6118 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
6119 if (err < 0)
6120 return err;
6121 }
6122 nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
Takashi Iwaice22e032008-01-11 17:38:35 +01006123 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
Takashi Iwai776e1842007-08-29 15:07:11 +02006124 err = add_control(spec, ALC_CTL_WIDGET_VOL,
6125 "Front Mic Boost",
6126 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
6127 if (err < 0)
6128 return err;
6129 }
6130 return 0;
6131}
6132
Kailang Yangdf694da2005-12-05 19:42:22 +01006133/* almost identical with ALC880 parser... */
6134static int alc882_parse_auto_config(struct hda_codec *codec)
6135{
6136 struct alc_spec *spec = codec->spec;
6137 int err = alc880_parse_auto_config(codec);
6138
6139 if (err < 0)
6140 return err;
Takashi Iwai776e1842007-08-29 15:07:11 +02006141 else if (!err)
6142 return 0; /* no config found */
6143
6144 err = alc_auto_add_mic_boost(codec);
6145 if (err < 0)
6146 return err;
6147
6148 /* hack - override the init verbs */
6149 spec->init_verbs[0] = alc882_auto_init_verbs;
6150
6151 return 1; /* config found */
Kailang Yangdf694da2005-12-05 19:42:22 +01006152}
6153
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006154/* additional initialization for auto-configuration model */
6155static void alc882_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01006156{
Kailang Yangdf694da2005-12-05 19:42:22 +01006157 alc882_auto_init_multi_out(codec);
6158 alc882_auto_init_hp_out(codec);
6159 alc882_auto_init_analog_input(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01006160}
6161
Linus Torvalds1da177e2005-04-16 15:20:36 -07006162static int patch_alc882(struct hda_codec *codec)
6163{
6164 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006165 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006166
Takashi Iwaie560d8d2005-09-09 14:21:46 +02006167 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006168 if (spec == NULL)
6169 return -ENOMEM;
6170
Linus Torvalds1da177e2005-04-16 15:20:36 -07006171 codec->spec = spec;
6172
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006173 board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
6174 alc882_models,
6175 alc882_cfg_tbl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006176
Kailang Yangdf694da2005-12-05 19:42:22 +01006177 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
Tobin Davis081d17c2007-02-15 17:46:18 +01006178 /* Pick up systems that don't supply PCI SSID */
6179 switch (codec->subsystem_id) {
6180 case 0x106b0c00: /* Mac Pro */
6181 board_config = ALC885_MACPRO;
6182 break;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006183 case 0x106b1000: /* iMac 24 */
6184 board_config = ALC885_IMAC24;
6185 break;
Jiang zhe3d5fa2e2008-01-10 13:05:47 +01006186 case 0x106b00a1: /* Macbook */
Takashi Iwai87350ad2007-08-16 18:19:38 +02006187 case 0x106b2c00: /* Macbook Pro rev3 */
6188 board_config = ALC885_MBP3;
6189 break;
Tobin Davis081d17c2007-02-15 17:46:18 +01006190 default:
6191 printk(KERN_INFO "hda_codec: Unknown model for ALC882, "
6192 "trying auto-probe from BIOS...\n");
6193 board_config = ALC882_AUTO;
6194 }
Kailang Yangdf694da2005-12-05 19:42:22 +01006195 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006196
Takashi Iwaif95474e2007-07-10 00:47:43 +02006197 alc_fix_pincfg(codec, alc882_pinfix_tbl, alc882_pin_fixes);
6198
Kailang Yangdf694da2005-12-05 19:42:22 +01006199 if (board_config == ALC882_AUTO) {
6200 /* automatic parse from the BIOS config */
6201 err = alc882_parse_auto_config(codec);
6202 if (err < 0) {
6203 alc_free(codec);
6204 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006205 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006206 printk(KERN_INFO
6207 "hda_codec: Cannot set up configuration "
6208 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01006209 board_config = ALC882_3ST_DIG;
6210 }
6211 }
6212
6213 if (board_config != ALC882_AUTO)
6214 setup_preset(spec, &alc882_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006215
6216 spec->stream_name_analog = "ALC882 Analog";
Kailang Yangdf694da2005-12-05 19:42:22 +01006217 spec->stream_analog_playback = &alc882_pcm_analog_playback;
6218 spec->stream_analog_capture = &alc882_pcm_analog_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006219
6220 spec->stream_name_digital = "ALC882 Digital";
Kailang Yangdf694da2005-12-05 19:42:22 +01006221 spec->stream_digital_playback = &alc882_pcm_digital_playback;
6222 spec->stream_digital_capture = &alc882_pcm_digital_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006223
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006224 if (!spec->adc_nids && spec->input_mux) {
Kailang Yangdf694da2005-12-05 19:42:22 +01006225 /* check whether NID 0x07 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +01006226 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006227 /* get type */
6228 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Kailang Yangdf694da2005-12-05 19:42:22 +01006229 if (wcap != AC_WID_AUD_IN) {
6230 spec->adc_nids = alc882_adc_nids_alt;
6231 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids_alt);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006232 spec->mixers[spec->num_mixers] =
6233 alc882_capture_alt_mixer;
Kailang Yangdf694da2005-12-05 19:42:22 +01006234 spec->num_mixers++;
6235 } else {
6236 spec->adc_nids = alc882_adc_nids;
6237 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids);
6238 spec->mixers[spec->num_mixers] = alc882_capture_mixer;
6239 spec->num_mixers++;
6240 }
6241 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006242
Takashi Iwai2134ea42008-01-10 16:53:55 +01006243 spec->vmaster_nid = 0x0c;
6244
Linus Torvalds1da177e2005-04-16 15:20:36 -07006245 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01006246 if (board_config == ALC882_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006247 spec->init_hook = alc882_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02006248#ifdef CONFIG_SND_HDA_POWER_SAVE
6249 if (!spec->loopback.amplist)
6250 spec->loopback.amplist = alc882_loopbacks;
6251#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006252
6253 return 0;
6254}
6255
6256/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006257 * ALC883 support
6258 *
6259 * ALC883 is almost identical with ALC880 but has cleaner and more flexible
6260 * configuration. Each pin widget can choose any input DACs and a mixer.
6261 * Each ADC is connected from a mixer of all inputs. This makes possible
6262 * 6-channel independent captures.
6263 *
6264 * In addition, an independent DAC for the multi-playback (not used in this
6265 * driver yet).
6266 */
6267#define ALC883_DIGOUT_NID 0x06
6268#define ALC883_DIGIN_NID 0x0a
6269
6270static hda_nid_t alc883_dac_nids[4] = {
6271 /* front, rear, clfe, rear_surr */
6272 0x02, 0x04, 0x03, 0x05
6273};
6274
6275static hda_nid_t alc883_adc_nids[2] = {
6276 /* ADC1-2 */
6277 0x08, 0x09,
6278};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006279
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006280/* input MUX */
6281/* FIXME: should be a matrix-type input source selection */
6282
6283static struct hda_input_mux alc883_capture_source = {
6284 .num_items = 4,
6285 .items = {
6286 { "Mic", 0x0 },
6287 { "Front Mic", 0x1 },
6288 { "Line", 0x2 },
6289 { "CD", 0x4 },
6290 },
6291};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006292
6293static struct hda_input_mux alc883_lenovo_101e_capture_source = {
6294 .num_items = 2,
6295 .items = {
6296 { "Mic", 0x1 },
6297 { "Line", 0x2 },
6298 },
6299};
6300
Kailang Yang272a5272007-05-14 11:00:38 +02006301static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
6302 .num_items = 4,
6303 .items = {
6304 { "Mic", 0x0 },
6305 { "iMic", 0x1 },
6306 { "Line", 0x2 },
6307 { "CD", 0x4 },
6308 },
6309};
6310
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006311#define alc883_mux_enum_info alc_mux_enum_info
6312#define alc883_mux_enum_get alc_mux_enum_get
6313
6314static int alc883_mux_enum_put(struct snd_kcontrol *kcontrol,
6315 struct snd_ctl_elem_value *ucontrol)
6316{
6317 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
6318 struct alc_spec *spec = codec->spec;
6319 const struct hda_input_mux *imux = spec->input_mux;
6320 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
6321 static hda_nid_t capture_mixers[3] = { 0x24, 0x23, 0x22 };
6322 hda_nid_t nid = capture_mixers[adc_idx];
6323 unsigned int *cur_val = &spec->cur_mux[adc_idx];
6324 unsigned int i, idx;
6325
6326 idx = ucontrol->value.enumerated.item[0];
6327 if (idx >= imux->num_items)
6328 idx = imux->num_items - 1;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006329 if (*cur_val == idx)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006330 return 0;
6331 for (i = 0; i < imux->num_items; i++) {
Takashi Iwai47fd8302007-08-10 17:11:07 +02006332 unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
6333 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006334 imux->items[i].index,
Takashi Iwai47fd8302007-08-10 17:11:07 +02006335 HDA_AMP_MUTE, v);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006336 }
6337 *cur_val = idx;
6338 return 1;
6339}
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006340
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006341/*
6342 * 2ch mode
6343 */
6344static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
6345 { 2, NULL }
6346};
6347
6348/*
6349 * 2ch mode
6350 */
6351static struct hda_verb alc883_3ST_ch2_init[] = {
6352 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6353 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6354 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
6355 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6356 { } /* end */
6357};
6358
6359/*
Tobin Davisb2011312007-09-17 12:45:11 +02006360 * 4ch mode
6361 */
6362static struct hda_verb alc883_3ST_ch4_init[] = {
6363 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6364 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6365 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6366 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6367 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6368 { } /* end */
6369};
6370
6371/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006372 * 6ch mode
6373 */
6374static struct hda_verb alc883_3ST_ch6_init[] = {
6375 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6376 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6377 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
6378 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6379 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6380 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6381 { } /* end */
6382};
6383
Tobin Davisb2011312007-09-17 12:45:11 +02006384static struct hda_channel_mode alc883_3ST_6ch_modes[3] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006385 { 2, alc883_3ST_ch2_init },
Tobin Davisb2011312007-09-17 12:45:11 +02006386 { 4, alc883_3ST_ch4_init },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006387 { 6, alc883_3ST_ch6_init },
6388};
6389
6390/*
6391 * 6ch mode
6392 */
6393static struct hda_verb alc883_sixstack_ch6_init[] = {
6394 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
6395 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6396 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6397 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6398 { } /* end */
6399};
6400
6401/*
6402 * 8ch mode
6403 */
6404static struct hda_verb alc883_sixstack_ch8_init[] = {
6405 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6406 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6407 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6408 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6409 { } /* end */
6410};
6411
6412static struct hda_channel_mode alc883_sixstack_modes[2] = {
6413 { 6, alc883_sixstack_ch6_init },
6414 { 8, alc883_sixstack_ch8_init },
6415};
6416
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01006417static struct hda_verb alc883_medion_eapd_verbs[] = {
6418 /* eanable EAPD on medion laptop */
6419 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
6420 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
6421 { }
6422};
6423
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006424/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
6425 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
6426 */
6427
6428static struct snd_kcontrol_new alc883_base_mixer[] = {
6429 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6430 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6431 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6432 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
6433 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6434 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
6435 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
6436 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
6437 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
6438 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
6439 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6440 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6441 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6442 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6443 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6444 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006445 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006446 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6447 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006448 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006449 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6450 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6451 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6452 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6453 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6454 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6455 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6456 {
6457 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6458 /* .name = "Capture Source", */
6459 .name = "Input Source",
6460 .count = 2,
6461 .info = alc883_mux_enum_info,
6462 .get = alc883_mux_enum_get,
6463 .put = alc883_mux_enum_put,
6464 },
6465 { } /* end */
6466};
6467
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01006468static struct snd_kcontrol_new alc883_mitac_mixer[] = {
6469 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6470 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6471 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6472 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
6473 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
6474 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
6475 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
6476 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6477 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6478 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6479 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6480 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
6481 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6482 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6483 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6484 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6485 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6486 {
6487 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6488 /* .name = "Capture Source", */
6489 .name = "Input Source",
6490 .count = 2,
6491 .info = alc883_mux_enum_info,
6492 .get = alc883_mux_enum_get,
6493 .put = alc883_mux_enum_put,
6494 },
6495 { } /* end */
6496};
6497
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006498static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
6499 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6500 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6501 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6502 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6503 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6504 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6505 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6506 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006507 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006508 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6509 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006510 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006511 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6512 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6513 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6514 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6515 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6516 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6517 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6518 {
6519 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6520 /* .name = "Capture Source", */
6521 .name = "Input Source",
6522 .count = 2,
6523 .info = alc883_mux_enum_info,
6524 .get = alc883_mux_enum_get,
6525 .put = alc883_mux_enum_put,
6526 },
6527 { } /* end */
6528};
6529
6530static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
6531 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6532 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6533 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6534 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
6535 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6536 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
6537 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
6538 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
6539 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6540 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6541 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6542 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6543 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6544 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006545 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006546 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6547 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006548 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006549 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6550 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6551 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6552 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6553 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6554 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6555 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6556 {
6557 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6558 /* .name = "Capture Source", */
6559 .name = "Input Source",
6560 .count = 2,
6561 .info = alc883_mux_enum_info,
6562 .get = alc883_mux_enum_get,
6563 .put = alc883_mux_enum_put,
6564 },
6565 { } /* end */
6566};
6567
Takashi Iwaid1d985f2006-11-23 19:27:12 +01006568static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
Tobin Davisc07584c2006-10-13 12:32:16 +02006569 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6570 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
6571 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6572 HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
6573 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6574 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
6575 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT),
6576 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
6577 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6578 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6579 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6580 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6581 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6582 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006583 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02006584 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6585 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006586 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02006587 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6588 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6589 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6590 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6591 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6592
6593 {
6594 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6595 /* .name = "Capture Source", */
6596 .name = "Input Source",
6597 .count = 1,
6598 .info = alc883_mux_enum_info,
6599 .get = alc883_mux_enum_get,
6600 .put = alc883_mux_enum_put,
6601 },
6602 { } /* end */
6603};
6604
Kailang Yangccc656c2006-10-17 12:32:26 +02006605static struct snd_kcontrol_new alc883_tagra_mixer[] = {
6606 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6607 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
6608 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6609 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6610 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
6611 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6612 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
6613 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
6614 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
6615 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6616 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6617 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6618 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6619 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006620 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02006621 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6622 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6623 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6624 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6625 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6626 {
6627 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6628 /* .name = "Capture Source", */
6629 .name = "Input Source",
6630 .count = 2,
6631 .info = alc883_mux_enum_info,
6632 .get = alc883_mux_enum_get,
6633 .put = alc883_mux_enum_put,
6634 },
6635 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006636};
Kailang Yangccc656c2006-10-17 12:32:26 +02006637
6638static struct snd_kcontrol_new alc883_tagra_2ch_mixer[] = {
6639 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6640 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
6641 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6642 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6643 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6644 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006645 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02006646 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6647 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6648 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6649 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6650 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6651 {
6652 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6653 /* .name = "Capture Source", */
6654 .name = "Input Source",
6655 .count = 2,
6656 .info = alc883_mux_enum_info,
6657 .get = alc883_mux_enum_get,
6658 .put = alc883_mux_enum_put,
6659 },
6660 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006661};
Kailang Yangccc656c2006-10-17 12:32:26 +02006662
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006663static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
6664 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6665 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6666 HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6667 HDA_BIND_MUTE("iSpeaker Playback Switch", 0x0d, 2, HDA_INPUT),
6668 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6669 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6670 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6671 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6672 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6673 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6674 {
6675 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6676 /* .name = "Capture Source", */
6677 .name = "Input Source",
6678 .count = 1,
6679 .info = alc883_mux_enum_info,
6680 .get = alc883_mux_enum_get,
6681 .put = alc883_mux_enum_put,
6682 },
6683 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006684};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006685
Kailang Yang272a5272007-05-14 11:00:38 +02006686static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
6687 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6688 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
6689 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
6690 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6691 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6692 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6693 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6694 HDA_CODEC_VOLUME("iMic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6695 HDA_CODEC_MUTE("iMic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6696 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6697 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6698 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6699 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6700 {
6701 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6702 /* .name = "Capture Source", */
6703 .name = "Input Source",
6704 .count = 2,
6705 .info = alc883_mux_enum_info,
6706 .get = alc883_mux_enum_get,
6707 .put = alc883_mux_enum_put,
6708 },
6709 { } /* end */
6710};
6711
6712static struct snd_kcontrol_new alc883_medion_md2_mixer[] = {
6713 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6714 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
6715 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
6716 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6717 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6718 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6719 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6720 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6721 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6722 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6723 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6724 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6725 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6726 {
6727 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6728 /* .name = "Capture Source", */
6729 .name = "Input Source",
6730 .count = 2,
6731 .info = alc883_mux_enum_info,
6732 .get = alc883_mux_enum_get,
6733 .put = alc883_mux_enum_put,
6734 },
6735 { } /* end */
6736};
6737
Claudio Matsuoka4723c022007-07-13 14:36:19 +02006738static struct snd_kcontrol_new alc888_6st_hp_mixer[] = {
Claudio Matsuokacd1e3b42007-07-06 12:10:01 +02006739 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6740 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6741 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
6742 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
6743 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
6744 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
6745 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
6746 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
6747 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
6748 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
6749 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6750 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6751 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6752 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6753 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6754 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6755 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6756 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6757 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6758 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
6759 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6760 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6761 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6762 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6763 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6764 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6765 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6766 {
6767 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6768 /* .name = "Capture Source", */
6769 .name = "Input Source",
6770 .count = 2,
6771 .info = alc883_mux_enum_info,
6772 .get = alc883_mux_enum_get,
6773 .put = alc883_mux_enum_put,
6774 },
6775 { } /* end */
6776};
6777
Claudio Matsuoka4723c022007-07-13 14:36:19 +02006778static struct snd_kcontrol_new alc888_3st_hp_mixer[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02006779 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6780 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6781 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
6782 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
6783 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
6784 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
6785 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
6786 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
6787 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6788 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6789 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6790 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6791 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6792 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6793 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6794 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6795 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6796 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
6797 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6798 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6799 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6800 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6801 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6802 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6803 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6804 {
6805 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6806 /* .name = "Capture Source", */
6807 .name = "Input Source",
6808 .count = 2,
6809 .info = alc883_mux_enum_info,
6810 .get = alc883_mux_enum_get,
6811 .put = alc883_mux_enum_put,
6812 },
6813 { } /* end */
6814};
6815
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01006816static struct snd_kcontrol_new alc888_6st_dell_mixer[] = {
6817 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6818 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6819 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
6820 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
6821 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
6822 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
6823 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
6824 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
6825 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
6826 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
6827 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6828 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6829 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6830 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6831 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6832 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6833 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6834 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6835 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6836 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
6837 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6838 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6839 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6840 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6841 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6842 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6843 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6844 {
6845 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6846 /* .name = "Capture Source", */
6847 .name = "Input Source",
6848 .count = 2,
6849 .info = alc883_mux_enum_info,
6850 .get = alc883_mux_enum_get,
6851 .put = alc883_mux_enum_put,
6852 },
6853 { } /* end */
6854};
6855
Tobin Davis2880a862007-08-07 11:50:26 +02006856static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02006857 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6858 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02006859 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02006860 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6861 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02006862 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6863 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6864 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02006865 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6866 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6867 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6868 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6869 {
6870 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6871 /* .name = "Capture Source", */
6872 .name = "Input Source",
6873 .count = 2,
6874 .info = alc883_mux_enum_info,
6875 .get = alc883_mux_enum_get,
6876 .put = alc883_mux_enum_put,
6877 },
6878 { } /* end */
Kailang Yangd1a991a2007-08-15 16:21:59 +02006879};
Tobin Davis2880a862007-08-07 11:50:26 +02006880
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006881static struct snd_kcontrol_new alc883_chmode_mixer[] = {
6882 {
6883 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6884 .name = "Channel Mode",
6885 .info = alc_ch_mode_info,
6886 .get = alc_ch_mode_get,
6887 .put = alc_ch_mode_put,
6888 },
6889 { } /* end */
6890};
6891
6892static struct hda_verb alc883_init_verbs[] = {
6893 /* ADC1: mute amp left and right */
6894 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6895 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
6896 /* ADC2: mute amp left and right */
6897 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6898 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
6899 /* Front mixer: unmute input/output amp left and right (volume = 0) */
6900 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6901 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6902 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6903 /* Rear mixer */
6904 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6905 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6906 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6907 /* CLFE mixer */
6908 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6909 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6910 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6911 /* Side mixer */
6912 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6913 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6914 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6915
Takashi Iwaicb53c622007-08-10 17:21:45 +02006916 /* mute analog input loopbacks */
6917 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6918 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6919 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6920 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6921 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006922
6923 /* Front Pin: output 0 (0x0c) */
6924 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6925 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6926 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
6927 /* Rear Pin: output 1 (0x0d) */
6928 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6929 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6930 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
6931 /* CLFE Pin: output 2 (0x0e) */
6932 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6933 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6934 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
6935 /* Side Pin: output 3 (0x0f) */
6936 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6937 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6938 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
6939 /* Mic (rear) pin: input vref at 80% */
6940 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6941 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6942 /* Front Mic pin: input vref at 80% */
6943 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6944 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6945 /* Line In pin: input */
6946 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
6947 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6948 /* Line-2 In: Headphone output (output 0 - 0x0c) */
6949 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6950 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6951 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
6952 /* CD pin widget for input */
6953 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
6954
6955 /* FIXME: use matrix-type input source selection */
6956 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
6957 /* Input mixer2 */
6958 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6959 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6960 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
6961 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
6962 /* Input mixer3 */
6963 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6964 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6965 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
6966 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
6967 { }
6968};
6969
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01006970/* toggle speaker-output according to the hp-jack state */
6971static void alc883_mitac_hp_automute(struct hda_codec *codec)
6972{
6973 unsigned int present;
6974
6975 present = snd_hda_codec_read(codec, 0x15, 0,
6976 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
6977 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
6978 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
6979 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
6980 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
6981}
6982
6983/* auto-toggle front mic */
6984/*
6985static void alc883_mitac_mic_automute(struct hda_codec *codec)
6986{
6987 unsigned int present;
6988 unsigned char bits;
6989
6990 present = snd_hda_codec_read(codec, 0x18, 0,
6991 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
6992 bits = present ? HDA_AMP_MUTE : 0;
6993 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
6994}
6995*/
6996
6997static void alc883_mitac_automute(struct hda_codec *codec)
6998{
6999 alc883_mitac_hp_automute(codec);
7000 /* alc883_mitac_mic_automute(codec); */
7001}
7002
7003static void alc883_mitac_unsol_event(struct hda_codec *codec,
7004 unsigned int res)
7005{
7006 switch (res >> 26) {
7007 case ALC880_HP_EVENT:
7008 alc883_mitac_hp_automute(codec);
7009 break;
7010 case ALC880_MIC_EVENT:
7011 /* alc883_mitac_mic_automute(codec); */
7012 break;
7013 }
7014}
7015
7016static struct hda_verb alc883_mitac_verbs[] = {
7017 /* HP */
7018 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7019 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7020 /* Subwoofer */
7021 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
7022 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7023
7024 /* enable unsolicited event */
7025 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7026 /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
7027
7028 { } /* end */
7029};
7030
Kailang Yangccc656c2006-10-17 12:32:26 +02007031static struct hda_verb alc883_tagra_verbs[] = {
7032 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7033 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7034
7035 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7036 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7037
7038 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
7039 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
7040 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
7041
7042 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007043 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
7044 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
7045 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
Kailang Yangccc656c2006-10-17 12:32:26 +02007046
7047 { } /* end */
7048};
7049
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007050static struct hda_verb alc883_lenovo_101e_verbs[] = {
7051 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7052 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
7053 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
7054 { } /* end */
7055};
7056
Kailang Yang272a5272007-05-14 11:00:38 +02007057static struct hda_verb alc883_lenovo_nb0763_verbs[] = {
7058 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7059 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7060 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7061 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7062 { } /* end */
7063};
7064
7065static struct hda_verb alc888_lenovo_ms7195_verbs[] = {
7066 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7067 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7068 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7069 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN},
7070 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7071 { } /* end */
7072};
7073
Kailang Yang189609a2007-08-20 11:31:23 +02007074static struct hda_verb alc883_haier_w66_verbs[] = {
7075 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7076 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7077
7078 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7079
7080 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
7081 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7082 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7083 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7084 { } /* end */
7085};
7086
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007087static struct hda_verb alc888_6st_hp_verbs[] = {
Claudio Matsuokacd1e3b42007-07-06 12:10:01 +02007088 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
7089 {0x15, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Rear : output 2 (0x0e) */
7090 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* CLFE : output 1 (0x0d) */
7091 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, /* Side : output 3 (0x0f) */
7092 { }
7093};
7094
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007095static struct hda_verb alc888_3st_hp_verbs[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007096 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
7097 {0x18, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */
7098 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */
7099 { }
7100};
7101
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007102static struct hda_verb alc888_6st_dell_verbs[] = {
7103 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
7104 {0x15, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Rear : output 1 (0x0e) */
7105 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* CLFE : output 2 (0x0d) */
7106 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, /* Side : output 3 (0x0f) */
7107 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7108 { }
7109};
7110
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007111static struct hda_verb alc888_3st_hp_2ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007112 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7113 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7114 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7115 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7116 { }
7117};
7118
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007119static struct hda_verb alc888_3st_hp_6ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007120 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7121 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7122 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7123 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7124 { }
7125};
7126
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007127static struct hda_channel_mode alc888_3st_hp_modes[2] = {
7128 { 2, alc888_3st_hp_2ch_init },
7129 { 6, alc888_3st_hp_6ch_init },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007130};
7131
Kailang Yang272a5272007-05-14 11:00:38 +02007132/* toggle front-jack and RCA according to the hp-jack state */
7133static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
7134{
7135 unsigned int present;
7136
7137 present = snd_hda_codec_read(codec, 0x1b, 0,
7138 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007139 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7140 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7141 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7142 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007143}
7144
7145/* toggle RCA according to the front-jack state */
7146static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec)
7147{
7148 unsigned int present;
7149
7150 present = snd_hda_codec_read(codec, 0x14, 0,
7151 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007152 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7153 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007154}
Takashi Iwai47fd8302007-08-10 17:11:07 +02007155
Kailang Yang272a5272007-05-14 11:00:38 +02007156static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec,
7157 unsigned int res)
7158{
7159 if ((res >> 26) == ALC880_HP_EVENT)
7160 alc888_lenovo_ms7195_front_automute(codec);
7161 if ((res >> 26) == ALC880_FRONT_EVENT)
7162 alc888_lenovo_ms7195_rca_automute(codec);
7163}
7164
7165static struct hda_verb alc883_medion_md2_verbs[] = {
7166 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7167 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7168
7169 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7170
7171 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7172 { } /* end */
7173};
7174
7175/* toggle speaker-output according to the hp-jack state */
7176static void alc883_medion_md2_automute(struct hda_codec *codec)
7177{
7178 unsigned int present;
7179
7180 present = snd_hda_codec_read(codec, 0x14, 0,
7181 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007182 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7183 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007184}
7185
7186static void alc883_medion_md2_unsol_event(struct hda_codec *codec,
7187 unsigned int res)
7188{
7189 if ((res >> 26) == ALC880_HP_EVENT)
7190 alc883_medion_md2_automute(codec);
7191}
7192
Kailang Yangccc656c2006-10-17 12:32:26 +02007193/* toggle speaker-output according to the hp-jack state */
7194static void alc883_tagra_automute(struct hda_codec *codec)
7195{
7196 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007197 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02007198
7199 present = snd_hda_codec_read(codec, 0x14, 0,
7200 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007201 bits = present ? HDA_AMP_MUTE : 0;
7202 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
7203 HDA_AMP_MUTE, bits);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02007204 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
7205 present ? 1 : 3);
Kailang Yangccc656c2006-10-17 12:32:26 +02007206}
7207
7208static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res)
7209{
7210 if ((res >> 26) == ALC880_HP_EVENT)
7211 alc883_tagra_automute(codec);
7212}
7213
Kailang Yang189609a2007-08-20 11:31:23 +02007214static void alc883_haier_w66_automute(struct hda_codec *codec)
7215{
7216 unsigned int present;
7217 unsigned char bits;
7218
7219 present = snd_hda_codec_read(codec, 0x1b, 0,
7220 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7221 bits = present ? 0x80 : 0;
7222 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7223 0x80, bits);
7224}
7225
7226static void alc883_haier_w66_unsol_event(struct hda_codec *codec,
7227 unsigned int res)
7228{
7229 if ((res >> 26) == ALC880_HP_EVENT)
7230 alc883_haier_w66_automute(codec);
7231}
7232
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007233static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
7234{
7235 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007236 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007237
7238 present = snd_hda_codec_read(codec, 0x14, 0,
7239 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007240 bits = present ? HDA_AMP_MUTE : 0;
7241 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7242 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007243}
7244
7245static void alc883_lenovo_101e_all_automute(struct hda_codec *codec)
7246{
7247 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007248 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007249
7250 present = snd_hda_codec_read(codec, 0x1b, 0,
7251 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007252 bits = present ? HDA_AMP_MUTE : 0;
7253 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7254 HDA_AMP_MUTE, bits);
7255 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7256 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007257}
7258
7259static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec,
7260 unsigned int res)
7261{
7262 if ((res >> 26) == ALC880_HP_EVENT)
7263 alc883_lenovo_101e_all_automute(codec);
7264 if ((res >> 26) == ALC880_FRONT_EVENT)
7265 alc883_lenovo_101e_ispeaker_automute(codec);
7266}
7267
Takashi Iwai676a9b52007-08-16 15:23:35 +02007268/* toggle speaker-output according to the hp-jack state */
7269static void alc883_acer_aspire_automute(struct hda_codec *codec)
7270{
7271 unsigned int present;
7272
7273 present = snd_hda_codec_read(codec, 0x14, 0,
7274 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7275 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7276 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7277 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
7278 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7279}
7280
7281static void alc883_acer_aspire_unsol_event(struct hda_codec *codec,
7282 unsigned int res)
7283{
7284 if ((res >> 26) == ALC880_HP_EVENT)
7285 alc883_acer_aspire_automute(codec);
7286}
7287
Kailang Yangd1a991a2007-08-15 16:21:59 +02007288static struct hda_verb alc883_acer_eapd_verbs[] = {
7289 /* HP Pin: output 0 (0x0c) */
7290 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7291 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7292 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7293 /* Front Pin: output 0 (0x0c) */
Takashi Iwai676a9b52007-08-16 15:23:35 +02007294 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7295 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangd1a991a2007-08-15 16:21:59 +02007296 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangd1a991a2007-08-15 16:21:59 +02007297 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
7298 /* eanable EAPD on medion laptop */
7299 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
7300 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
Takashi Iwai676a9b52007-08-16 15:23:35 +02007301 /* enable unsolicited event */
7302 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangd1a991a2007-08-15 16:21:59 +02007303 { }
7304};
7305
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007306static void alc888_6st_dell_front_automute(struct hda_codec *codec)
7307{
7308 unsigned int present;
7309
7310 present = snd_hda_codec_read(codec, 0x1b, 0,
7311 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7312 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7313 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7314 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7315 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7316 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
7317 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7318 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
7319 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7320}
7321
7322static void alc888_6st_dell_unsol_event(struct hda_codec *codec,
7323 unsigned int res)
7324{
7325 switch (res >> 26) {
7326 case ALC880_HP_EVENT:
7327 printk("hp_event\n");
7328 alc888_6st_dell_front_automute(codec);
7329 break;
7330 }
7331}
7332
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007333/*
7334 * generic initialization of ADC, input mixers and output mixers
7335 */
7336static struct hda_verb alc883_auto_init_verbs[] = {
7337 /*
7338 * Unmute ADC0-2 and set the default input to mic-in
7339 */
7340 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7341 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7342 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
7343 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7344
Takashi Iwaicb53c622007-08-10 17:21:45 +02007345 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007346 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007347 * Note: PASD motherboards uses the Line In 2 as the input for
7348 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007349 */
7350 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02007351 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7352 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7353 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7354 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7355 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007356
7357 /*
7358 * Set up output mixers (0x0c - 0x0f)
7359 */
7360 /* set vol=0 to output mixers */
7361 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7362 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7363 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7364 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7365 /* set up input amps for analog loopback */
7366 /* Amp Indices: DAC = 0, mixer = 1 */
7367 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7368 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7369 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7370 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7371 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7372 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7373 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7374 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7375 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7376 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7377
7378 /* FIXME: use matrix-type input source selection */
7379 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
7380 /* Input mixer1 */
7381 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7382 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7383 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007384 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007385 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
7386 /* Input mixer2 */
7387 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7388 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7389 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007390 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
Andy Shevchenkoe3cde642007-12-03 16:50:58 +01007391 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007392
7393 { }
7394};
7395
7396/* capture mixer elements */
7397static struct snd_kcontrol_new alc883_capture_mixer[] = {
7398 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7399 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7400 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7401 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7402 {
7403 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7404 /* The multiple "Capture Source" controls confuse alsamixer
7405 * So call somewhat different..
7406 * FIXME: the controls appear in the "playback" view!
7407 */
7408 /* .name = "Capture Source", */
7409 .name = "Input Source",
7410 .count = 2,
7411 .info = alc882_mux_enum_info,
7412 .get = alc882_mux_enum_get,
7413 .put = alc882_mux_enum_put,
7414 },
7415 { } /* end */
7416};
7417
Takashi Iwaicb53c622007-08-10 17:21:45 +02007418#ifdef CONFIG_SND_HDA_POWER_SAVE
7419#define alc883_loopbacks alc880_loopbacks
7420#endif
7421
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007422/* pcm configuration: identiacal with ALC880 */
7423#define alc883_pcm_analog_playback alc880_pcm_analog_playback
7424#define alc883_pcm_analog_capture alc880_pcm_analog_capture
7425#define alc883_pcm_digital_playback alc880_pcm_digital_playback
7426#define alc883_pcm_digital_capture alc880_pcm_digital_capture
7427
7428/*
7429 * configuration and preset
7430 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007431static const char *alc883_models[ALC883_MODEL_LAST] = {
7432 [ALC883_3ST_2ch_DIG] = "3stack-dig",
7433 [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
7434 [ALC883_3ST_6ch] = "3stack-6ch",
7435 [ALC883_6ST_DIG] = "6stack-dig",
7436 [ALC883_TARGA_DIG] = "targa-dig",
7437 [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007438 [ALC883_ACER] = "acer",
Tobin Davis2880a862007-08-07 11:50:26 +02007439 [ALC883_ACER_ASPIRE] = "acer-aspire",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007440 [ALC883_MEDION] = "medion",
Kailang Yang272a5272007-05-14 11:00:38 +02007441 [ALC883_MEDION_MD2] = "medion-md2",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007442 [ALC883_LAPTOP_EAPD] = "laptop-eapd",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007443 [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
Kailang Yang272a5272007-05-14 11:00:38 +02007444 [ALC883_LENOVO_NB0763] = "lenovo-nb0763",
7445 [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
Kailang Yang189609a2007-08-20 11:31:23 +02007446 [ALC883_HAIER_W66] = "haier-w66",
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007447 [ALC888_6ST_HP] = "6stack-hp",
7448 [ALC888_3ST_HP] = "3stack-hp",
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007449 [ALC888_6ST_DELL] = "6stack-dell",
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007450 [ALC883_MITAC] = "mitac",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007451 [ALC883_AUTO] = "auto",
7452};
7453
7454static struct snd_pci_quirk alc883_cfg_tbl[] = {
7455 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007456 SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
7457 SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
7458 SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
7459 SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), /* default Acer */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007460 SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
Tobin Davisfebe3372007-06-12 11:27:46 +02007461 SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007462 SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
7463 SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
7464 SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC888_6ST_HP),
7465 SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007466 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007467 SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
7468 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
7469 SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
Tobin Davis57b14f22007-04-18 23:05:36 +02007470 SND_PCI_QUIRK(0x1458, 0xa002, "MSI", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007471 SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
7472 SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
7473 SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
7474 SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
7475 SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
7476 SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
7477 SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
7478 SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
7479 SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
7480 SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
7481 SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
7482 SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
7483 SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007484 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
7485 SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
Tobin Davis799f88a2007-05-29 14:29:08 +02007486 SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
Leonard Norrgard2a296cb2007-01-08 11:28:22 +01007487 SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
Tobin Davis2dcd5222007-07-10 17:04:57 +02007488 SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007489 SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007490 SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
7491 SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD),
Daniel T Chene60623b2007-05-29 03:41:55 -04007492 SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007493 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
Kailang Yang272a5272007-05-14 11:00:38 +02007494 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
Kailang Yang272a5272007-05-14 11:00:38 +02007495 SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007496 SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
7497 SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Kailang Yang272a5272007-05-14 11:00:38 +02007498 SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
Kailang Yang189609a2007-08-20 11:31:23 +02007499 SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007500 SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007501 {}
7502};
7503
7504static struct alc_config_preset alc883_presets[] = {
7505 [ALC883_3ST_2ch_DIG] = {
7506 .mixers = { alc883_3ST_2ch_mixer },
7507 .init_verbs = { alc883_init_verbs },
7508 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7509 .dac_nids = alc883_dac_nids,
7510 .dig_out_nid = ALC883_DIGOUT_NID,
7511 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
7512 .adc_nids = alc883_adc_nids,
7513 .dig_in_nid = ALC883_DIGIN_NID,
7514 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7515 .channel_mode = alc883_3ST_2ch_modes,
7516 .input_mux = &alc883_capture_source,
7517 },
7518 [ALC883_3ST_6ch_DIG] = {
7519 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
7520 .init_verbs = { alc883_init_verbs },
7521 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7522 .dac_nids = alc883_dac_nids,
7523 .dig_out_nid = ALC883_DIGOUT_NID,
7524 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
7525 .adc_nids = alc883_adc_nids,
7526 .dig_in_nid = ALC883_DIGIN_NID,
7527 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
7528 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02007529 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007530 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007531 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007532 [ALC883_3ST_6ch] = {
7533 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
7534 .init_verbs = { alc883_init_verbs },
7535 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7536 .dac_nids = alc883_dac_nids,
7537 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
7538 .adc_nids = alc883_adc_nids,
7539 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
7540 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02007541 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007542 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007543 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007544 [ALC883_6ST_DIG] = {
7545 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
7546 .init_verbs = { alc883_init_verbs },
7547 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7548 .dac_nids = alc883_dac_nids,
7549 .dig_out_nid = ALC883_DIGOUT_NID,
7550 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
7551 .adc_nids = alc883_adc_nids,
7552 .dig_in_nid = ALC883_DIGIN_NID,
7553 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
7554 .channel_mode = alc883_sixstack_modes,
7555 .input_mux = &alc883_capture_source,
7556 },
Kailang Yangccc656c2006-10-17 12:32:26 +02007557 [ALC883_TARGA_DIG] = {
7558 .mixers = { alc883_tagra_mixer, alc883_chmode_mixer },
7559 .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
7560 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7561 .dac_nids = alc883_dac_nids,
7562 .dig_out_nid = ALC883_DIGOUT_NID,
7563 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
7564 .adc_nids = alc883_adc_nids,
7565 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
7566 .channel_mode = alc883_3ST_6ch_modes,
7567 .need_dac_fix = 1,
7568 .input_mux = &alc883_capture_source,
7569 .unsol_event = alc883_tagra_unsol_event,
7570 .init_hook = alc883_tagra_automute,
7571 },
7572 [ALC883_TARGA_2ch_DIG] = {
7573 .mixers = { alc883_tagra_2ch_mixer},
7574 .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
7575 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7576 .dac_nids = alc883_dac_nids,
7577 .dig_out_nid = ALC883_DIGOUT_NID,
7578 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
7579 .adc_nids = alc883_adc_nids,
7580 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7581 .channel_mode = alc883_3ST_2ch_modes,
7582 .input_mux = &alc883_capture_source,
7583 .unsol_event = alc883_tagra_unsol_event,
7584 .init_hook = alc883_tagra_automute,
7585 },
Vladimir Avdoninbab282b92006-08-22 13:31:58 +02007586 [ALC883_ACER] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02007587 .mixers = { alc883_base_mixer },
Vladimir Avdoninbab282b92006-08-22 13:31:58 +02007588 /* On TravelMate laptops, GPIO 0 enables the internal speaker
7589 * and the headphone jack. Turn this on and rely on the
7590 * standard mute methods whenever the user wants to turn
7591 * these outputs off.
7592 */
7593 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
7594 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7595 .dac_nids = alc883_dac_nids,
7596 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
7597 .adc_nids = alc883_adc_nids,
7598 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7599 .channel_mode = alc883_3ST_2ch_modes,
7600 .input_mux = &alc883_capture_source,
7601 },
Tobin Davis2880a862007-08-07 11:50:26 +02007602 [ALC883_ACER_ASPIRE] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02007603 .mixers = { alc883_acer_aspire_mixer },
Kailang Yangd1a991a2007-08-15 16:21:59 +02007604 .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs },
Tobin Davis2880a862007-08-07 11:50:26 +02007605 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7606 .dac_nids = alc883_dac_nids,
7607 .dig_out_nid = ALC883_DIGOUT_NID,
7608 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
7609 .adc_nids = alc883_adc_nids,
7610 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7611 .channel_mode = alc883_3ST_2ch_modes,
7612 .input_mux = &alc883_capture_source,
Takashi Iwai676a9b52007-08-16 15:23:35 +02007613 .unsol_event = alc883_acer_aspire_unsol_event,
7614 .init_hook = alc883_acer_aspire_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +02007615 },
Tobin Davisc07584c2006-10-13 12:32:16 +02007616 [ALC883_MEDION] = {
7617 .mixers = { alc883_fivestack_mixer,
7618 alc883_chmode_mixer },
7619 .init_verbs = { alc883_init_verbs,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007620 alc883_medion_eapd_verbs },
Tobin Davisc07584c2006-10-13 12:32:16 +02007621 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7622 .dac_nids = alc883_dac_nids,
7623 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
7624 .adc_nids = alc883_adc_nids,
7625 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
7626 .channel_mode = alc883_sixstack_modes,
7627 .input_mux = &alc883_capture_source,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007628 },
Kailang Yang272a5272007-05-14 11:00:38 +02007629 [ALC883_MEDION_MD2] = {
7630 .mixers = { alc883_medion_md2_mixer},
7631 .init_verbs = { alc883_init_verbs, alc883_medion_md2_verbs},
7632 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7633 .dac_nids = alc883_dac_nids,
7634 .dig_out_nid = ALC883_DIGOUT_NID,
7635 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
7636 .adc_nids = alc883_adc_nids,
7637 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7638 .channel_mode = alc883_3ST_2ch_modes,
7639 .input_mux = &alc883_capture_source,
7640 .unsol_event = alc883_medion_md2_unsol_event,
7641 .init_hook = alc883_medion_md2_automute,
7642 },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007643 [ALC883_LAPTOP_EAPD] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02007644 .mixers = { alc883_base_mixer },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007645 .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
7646 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7647 .dac_nids = alc883_dac_nids,
7648 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
7649 .adc_nids = alc883_adc_nids,
7650 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7651 .channel_mode = alc883_3ST_2ch_modes,
7652 .input_mux = &alc883_capture_source,
7653 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007654 [ALC883_LENOVO_101E_2ch] = {
7655 .mixers = { alc883_lenovo_101e_2ch_mixer},
7656 .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
7657 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7658 .dac_nids = alc883_dac_nids,
7659 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
7660 .adc_nids = alc883_adc_nids,
7661 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7662 .channel_mode = alc883_3ST_2ch_modes,
7663 .input_mux = &alc883_lenovo_101e_capture_source,
7664 .unsol_event = alc883_lenovo_101e_unsol_event,
7665 .init_hook = alc883_lenovo_101e_all_automute,
7666 },
Kailang Yang272a5272007-05-14 11:00:38 +02007667 [ALC883_LENOVO_NB0763] = {
7668 .mixers = { alc883_lenovo_nb0763_mixer },
7669 .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
7670 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7671 .dac_nids = alc883_dac_nids,
7672 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
7673 .adc_nids = alc883_adc_nids,
7674 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7675 .channel_mode = alc883_3ST_2ch_modes,
7676 .need_dac_fix = 1,
7677 .input_mux = &alc883_lenovo_nb0763_capture_source,
7678 .unsol_event = alc883_medion_md2_unsol_event,
7679 .init_hook = alc883_medion_md2_automute,
7680 },
7681 [ALC888_LENOVO_MS7195_DIG] = {
7682 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
7683 .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs},
7684 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7685 .dac_nids = alc883_dac_nids,
7686 .dig_out_nid = ALC883_DIGOUT_NID,
7687 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
7688 .adc_nids = alc883_adc_nids,
7689 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
7690 .channel_mode = alc883_3ST_6ch_modes,
7691 .need_dac_fix = 1,
7692 .input_mux = &alc883_capture_source,
7693 .unsol_event = alc883_lenovo_ms7195_unsol_event,
7694 .init_hook = alc888_lenovo_ms7195_front_automute,
Kailang Yang189609a2007-08-20 11:31:23 +02007695 },
7696 [ALC883_HAIER_W66] = {
7697 .mixers = { alc883_tagra_2ch_mixer},
7698 .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs},
7699 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7700 .dac_nids = alc883_dac_nids,
7701 .dig_out_nid = ALC883_DIGOUT_NID,
7702 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
7703 .adc_nids = alc883_adc_nids,
7704 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7705 .channel_mode = alc883_3ST_2ch_modes,
7706 .input_mux = &alc883_capture_source,
7707 .unsol_event = alc883_haier_w66_unsol_event,
7708 .init_hook = alc883_haier_w66_automute,
Kailang Yang272a5272007-05-14 11:00:38 +02007709 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007710 [ALC888_6ST_HP] = {
7711 .mixers = { alc888_6st_hp_mixer, alc883_chmode_mixer },
7712 .init_verbs = { alc883_init_verbs, alc888_6st_hp_verbs },
Claudio Matsuokacd1e3b42007-07-06 12:10:01 +02007713 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7714 .dac_nids = alc883_dac_nids,
7715 .dig_out_nid = ALC883_DIGOUT_NID,
7716 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
7717 .adc_nids = alc883_adc_nids,
7718 .dig_in_nid = ALC883_DIGIN_NID,
7719 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
7720 .channel_mode = alc883_sixstack_modes,
7721 .input_mux = &alc883_capture_source,
7722 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007723 [ALC888_3ST_HP] = {
7724 .mixers = { alc888_3st_hp_mixer, alc883_chmode_mixer },
7725 .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007726 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7727 .dac_nids = alc883_dac_nids,
7728 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
7729 .adc_nids = alc883_adc_nids,
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007730 .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
7731 .channel_mode = alc888_3st_hp_modes,
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007732 .need_dac_fix = 1,
7733 .input_mux = &alc883_capture_source,
7734 },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007735 [ALC888_6ST_DELL] = {
7736 .mixers = { alc888_6st_dell_mixer, alc883_chmode_mixer },
7737 .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
7738 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7739 .dac_nids = alc883_dac_nids,
7740 .dig_out_nid = ALC883_DIGOUT_NID,
7741 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
7742 .adc_nids = alc883_adc_nids,
7743 .dig_in_nid = ALC883_DIGIN_NID,
7744 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
7745 .channel_mode = alc883_sixstack_modes,
7746 .input_mux = &alc883_capture_source,
7747 .unsol_event = alc888_6st_dell_unsol_event,
7748 .init_hook = alc888_6st_dell_front_automute,
7749 },
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007750 [ALC883_MITAC] = {
7751 .mixers = { alc883_mitac_mixer },
7752 .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
7753 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7754 .dac_nids = alc883_dac_nids,
7755 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
7756 .adc_nids = alc883_adc_nids,
7757 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7758 .channel_mode = alc883_3ST_2ch_modes,
7759 .input_mux = &alc883_capture_source,
7760 .unsol_event = alc883_mitac_unsol_event,
7761 .init_hook = alc883_mitac_automute,
7762 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007763};
7764
7765
7766/*
7767 * BIOS auto configuration
7768 */
7769static void alc883_auto_set_output_and_unmute(struct hda_codec *codec,
7770 hda_nid_t nid, int pin_type,
7771 int dac_idx)
7772{
7773 /* set as output */
7774 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007775 int idx;
7776
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007777 if (spec->multiout.dac_nids[dac_idx] == 0x25)
7778 idx = 4;
7779 else
7780 idx = spec->multiout.dac_nids[dac_idx] - 2;
7781
7782 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
7783 pin_type);
7784 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
7785 AMP_OUT_UNMUTE);
7786 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
7787
7788}
7789
7790static void alc883_auto_init_multi_out(struct hda_codec *codec)
7791{
7792 struct alc_spec *spec = codec->spec;
7793 int i;
7794
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007795 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007796 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007797 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02007798 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007799 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02007800 alc883_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007801 i);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007802 }
7803}
7804
7805static void alc883_auto_init_hp_out(struct hda_codec *codec)
7806{
7807 struct alc_spec *spec = codec->spec;
7808 hda_nid_t pin;
7809
Takashi Iwaieb06ed82006-09-20 17:10:27 +02007810 pin = spec->autocfg.hp_pins[0];
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007811 if (pin) /* connect to front */
7812 /* use dac 0 */
7813 alc883_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
7814}
7815
7816#define alc883_is_input_pin(nid) alc880_is_input_pin(nid)
7817#define ALC883_PIN_CD_NID ALC880_PIN_CD_NID
7818
7819static void alc883_auto_init_analog_input(struct hda_codec *codec)
7820{
7821 struct alc_spec *spec = codec->spec;
7822 int i;
7823
7824 for (i = 0; i < AUTO_PIN_LAST; i++) {
7825 hda_nid_t nid = spec->autocfg.input_pins[i];
7826 if (alc883_is_input_pin(nid)) {
7827 snd_hda_codec_write(codec, nid, 0,
7828 AC_VERB_SET_PIN_WIDGET_CONTROL,
7829 (i <= AUTO_PIN_FRONT_MIC ?
7830 PIN_VREF80 : PIN_IN));
7831 if (nid != ALC883_PIN_CD_NID)
7832 snd_hda_codec_write(codec, nid, 0,
7833 AC_VERB_SET_AMP_GAIN_MUTE,
7834 AMP_OUT_MUTE);
7835 }
7836 }
7837}
7838
7839/* almost identical with ALC880 parser... */
7840static int alc883_parse_auto_config(struct hda_codec *codec)
7841{
7842 struct alc_spec *spec = codec->spec;
7843 int err = alc880_parse_auto_config(codec);
7844
7845 if (err < 0)
7846 return err;
Takashi Iwai776e1842007-08-29 15:07:11 +02007847 else if (!err)
7848 return 0; /* no config found */
7849
7850 err = alc_auto_add_mic_boost(codec);
7851 if (err < 0)
7852 return err;
7853
7854 /* hack - override the init verbs */
7855 spec->init_verbs[0] = alc883_auto_init_verbs;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007856 spec->mixers[spec->num_mixers] = alc883_capture_mixer;
7857 spec->num_mixers++;
Takashi Iwai776e1842007-08-29 15:07:11 +02007858
7859 return 1; /* config found */
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007860}
7861
7862/* additional initialization for auto-configuration model */
7863static void alc883_auto_init(struct hda_codec *codec)
7864{
7865 alc883_auto_init_multi_out(codec);
7866 alc883_auto_init_hp_out(codec);
7867 alc883_auto_init_analog_input(codec);
7868}
7869
7870static int patch_alc883(struct hda_codec *codec)
7871{
7872 struct alc_spec *spec;
7873 int err, board_config;
7874
7875 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
7876 if (spec == NULL)
7877 return -ENOMEM;
7878
7879 codec->spec = spec;
7880
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007881 board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST,
7882 alc883_models,
7883 alc883_cfg_tbl);
7884 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007885 printk(KERN_INFO "hda_codec: Unknown model for ALC883, "
7886 "trying auto-probe from BIOS...\n");
7887 board_config = ALC883_AUTO;
7888 }
7889
7890 if (board_config == ALC883_AUTO) {
7891 /* automatic parse from the BIOS config */
7892 err = alc883_parse_auto_config(codec);
7893 if (err < 0) {
7894 alc_free(codec);
7895 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007896 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007897 printk(KERN_INFO
7898 "hda_codec: Cannot set up configuration "
7899 "from BIOS. Using base mode...\n");
7900 board_config = ALC883_3ST_2ch_DIG;
7901 }
7902 }
7903
7904 if (board_config != ALC883_AUTO)
7905 setup_preset(spec, &alc883_presets[board_config]);
7906
7907 spec->stream_name_analog = "ALC883 Analog";
7908 spec->stream_analog_playback = &alc883_pcm_analog_playback;
7909 spec->stream_analog_capture = &alc883_pcm_analog_capture;
7910
7911 spec->stream_name_digital = "ALC883 Digital";
7912 spec->stream_digital_playback = &alc883_pcm_digital_playback;
7913 spec->stream_digital_capture = &alc883_pcm_digital_capture;
7914
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007915 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02007916 spec->adc_nids = alc883_adc_nids;
7917 spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
7918 }
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007919
Takashi Iwai2134ea42008-01-10 16:53:55 +01007920 spec->vmaster_nid = 0x0c;
7921
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007922 codec->patch_ops = alc_patch_ops;
7923 if (board_config == ALC883_AUTO)
7924 spec->init_hook = alc883_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02007925#ifdef CONFIG_SND_HDA_POWER_SAVE
7926 if (!spec->loopback.amplist)
7927 spec->loopback.amplist = alc883_loopbacks;
7928#endif
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007929
7930 return 0;
7931}
7932
7933/*
Kailang Yangdf694da2005-12-05 19:42:22 +01007934 * ALC262 support
7935 */
7936
7937#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID
7938#define ALC262_DIGIN_NID ALC880_DIGIN_NID
7939
7940#define alc262_dac_nids alc260_dac_nids
7941#define alc262_adc_nids alc882_adc_nids
7942#define alc262_adc_nids_alt alc882_adc_nids_alt
7943
7944#define alc262_modes alc260_modes
Takashi Iwaic5f2ea02005-12-06 18:54:31 +01007945#define alc262_capture_source alc882_capture_source
Kailang Yangdf694da2005-12-05 19:42:22 +01007946
7947static struct snd_kcontrol_new alc262_base_mixer[] = {
7948 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7949 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7950 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7951 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7952 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7953 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7954 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7955 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01007956 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01007957 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
7958 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01007959 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01007960 /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
7961 HDA_CODEC_MUTE("PC Beelp Playback Switch", 0x0b, 0x05, HDA_INPUT), */
7962 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
7963 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7964 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7965 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01007966 { } /* end */
Takashi Iwai834be882006-03-01 14:16:17 +01007967};
7968
Kailang Yangccc656c2006-10-17 12:32:26 +02007969static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
7970 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7971 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7972 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7973 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7974 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7975 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7976 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7977 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01007978 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007979 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
7980 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01007981 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007982 /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
7983 HDA_CODEC_MUTE("PC Beelp Playback Switch", 0x0b, 0x05, HDA_INPUT), */
7984 /*HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),*/
7985 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7986 { } /* end */
7987};
7988
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007989static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
7990 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7991 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7992 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7993 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7994 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
7995
7996 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7997 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01007998 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007999 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8000 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008001 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008002 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8003 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8004 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8005 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8006 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
8007 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT),
8008 HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
8009 HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
8010 { } /* end */
8011};
8012
Kailang Yangcd7509a2007-01-26 18:33:17 +01008013static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
8014 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8015 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8016 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8017 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8018 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8019 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
8020 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
8021 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008022 HDA_CODEC_VOLUME("Front Mic Boost", 0x1a, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01008023 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
8024 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
8025 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8026 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8027 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
8028 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT),
8029 { } /* end */
8030};
8031
8032static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
8033 HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8034 HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008035 HDA_CODEC_VOLUME("Rear Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01008036 { } /* end */
8037};
8038
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008039static struct hda_bind_ctls alc262_hp_t5735_bind_front_vol = {
8040 .ops = &snd_hda_bind_vol,
8041 .values = {
8042 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
8043 HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
8044 0
8045 },
8046};
8047
8048static struct hda_bind_ctls alc262_hp_t5735_bind_front_sw = {
8049 .ops = &snd_hda_bind_sw,
8050 .values = {
8051 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
8052 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
8053 0
8054 },
8055};
8056
8057/* mute/unmute internal speaker according to the hp jack and mute state */
8058static void alc262_hp_t5735_automute(struct hda_codec *codec, int force)
8059{
8060 struct alc_spec *spec = codec->spec;
8061 unsigned int mute;
8062
8063 if (force || !spec->sense_updated) {
8064 unsigned int present;
8065 present = snd_hda_codec_read(codec, 0x15, 0,
8066 AC_VERB_GET_PIN_SENSE, 0);
8067 spec->jack_present = (present & 0x80000000) != 0;
8068 spec->sense_updated = 1;
8069 }
8070 if (spec->jack_present)
8071 mute = (0x7080 | ((0)<<8)); /* mute internal speaker */
8072 else /* unmute internal speaker if necessary */
8073 mute = (0x7000 | ((0)<<8));
8074 snd_hda_codec_write(codec, 0x0c, 0,
8075 AC_VERB_SET_AMP_GAIN_MUTE, mute );
8076}
8077
8078static void alc262_hp_t5735_unsol_event(struct hda_codec *codec,
8079 unsigned int res)
8080{
8081 if ((res >> 26) != ALC880_HP_EVENT)
8082 return;
8083 alc262_hp_t5735_automute(codec, 1);
8084}
8085
8086static void alc262_hp_t5735_init_hook(struct hda_codec *codec)
8087{
8088 alc262_hp_t5735_automute(codec, 1);
8089}
8090
8091static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
8092 HDA_BIND_VOL("PCM Playback Volume", &alc262_hp_t5735_bind_front_vol),
8093 HDA_BIND_SW("PCM Playback Switch",&alc262_hp_t5735_bind_front_sw),
8094 HDA_CODEC_VOLUME("LineOut Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8095 HDA_CODEC_MUTE("LineOut Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8096 HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8097 HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8098 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8099 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8100 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8101 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8102 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8103 { } /* end */
8104};
8105
8106static struct hda_verb alc262_hp_t5735_verbs[] = {
8107 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8108 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8109
8110 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8111 { }
8112};
8113
Kailang Yang8c427222008-01-10 13:03:59 +01008114static struct hda_bind_ctls alc262_hp_rp5700_bind_front_vol = {
8115 .ops = &snd_hda_bind_vol,
8116 .values = {
8117 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
8118 HDA_COMPOSE_AMP_VAL(0x0e, 3, 0, HDA_OUTPUT),
8119 0
8120 },
8121};
8122
8123static struct hda_bind_ctls alc262_hp_rp5700_bind_front_sw = {
8124 .ops = &snd_hda_bind_sw,
8125 .values = {
8126 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
8127 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT),
8128 0
8129 },
8130};
8131
8132static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
8133 HDA_BIND_VOL("PCM Playback Volume", &alc262_hp_rp5700_bind_front_vol),
8134 HDA_BIND_SW("PCM Playback Switch", &alc262_hp_rp5700_bind_front_sw),
8135 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8136 HDA_CODEC_MUTE("Master Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8137 HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
8138 HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
8139 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
8140 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
8141 { } /* end */
8142};
8143
8144static struct hda_verb alc262_hp_rp5700_verbs[] = {
8145 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8146 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8147 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8148 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8149 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8150 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
8151 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
8152 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
8153 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
8154 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
8155 {}
8156};
8157
8158static struct hda_input_mux alc262_hp_rp5700_capture_source = {
8159 .num_items = 1,
8160 .items = {
8161 { "Line", 0x1 },
8162 },
8163};
8164
Takashi Iwai0724ea22007-08-23 00:31:43 +02008165/* bind hp and internal speaker mute (with plug check) */
8166static int alc262_sony_master_sw_put(struct snd_kcontrol *kcontrol,
8167 struct snd_ctl_elem_value *ucontrol)
8168{
8169 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
8170 long *valp = ucontrol->value.integer.value;
8171 int change;
8172
8173 /* change hp mute */
8174 change = snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0,
8175 HDA_AMP_MUTE,
8176 valp[0] ? 0 : HDA_AMP_MUTE);
8177 change |= snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0,
8178 HDA_AMP_MUTE,
8179 valp[1] ? 0 : HDA_AMP_MUTE);
8180 if (change) {
8181 /* change speaker according to HP jack state */
8182 struct alc_spec *spec = codec->spec;
8183 unsigned int mute;
8184 if (spec->jack_present)
8185 mute = HDA_AMP_MUTE;
8186 else
8187 mute = snd_hda_codec_amp_read(codec, 0x15, 0,
8188 HDA_OUTPUT, 0);
8189 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8190 HDA_AMP_MUTE, mute);
8191 }
8192 return change;
8193}
Takashi Iwai5b319542007-07-26 11:49:22 +02008194
Kailang Yang272a5272007-05-14 11:00:38 +02008195static struct snd_kcontrol_new alc262_sony_mixer[] = {
Takashi Iwai0724ea22007-08-23 00:31:43 +02008196 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8197 {
8198 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8199 .name = "Master Playback Switch",
8200 .info = snd_hda_mixer_amp_switch_info,
8201 .get = snd_hda_mixer_amp_switch_get,
8202 .put = alc262_sony_master_sw_put,
8203 .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
8204 },
Kailang Yang272a5272007-05-14 11:00:38 +02008205 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8206 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8207 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8208 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
8209 { } /* end */
8210};
8211
Kailang Yang83c34212007-07-05 11:43:05 +02008212static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
8213 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8214 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8215 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8216 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8217 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8218 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8219 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
8220 { } /* end */
8221};
Kailang Yang272a5272007-05-14 11:00:38 +02008222
Kailang Yangdf694da2005-12-05 19:42:22 +01008223#define alc262_capture_mixer alc882_capture_mixer
8224#define alc262_capture_alt_mixer alc882_capture_alt_mixer
8225
8226/*
8227 * generic initialization of ADC, input mixers and output mixers
8228 */
8229static struct hda_verb alc262_init_verbs[] = {
8230 /*
8231 * Unmute ADC0-2 and set the default input to mic-in
8232 */
8233 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8234 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8235 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8236 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8237 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8238 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8239
Takashi Iwaicb53c622007-08-10 17:21:45 +02008240 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01008241 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008242 * Note: PASD motherboards uses the Line In 2 as the input for
8243 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01008244 */
8245 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02008246 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8247 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8248 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8249 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8250 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01008251
8252 /*
8253 * Set up output mixers (0x0c - 0x0e)
8254 */
8255 /* set vol=0 to output mixers */
8256 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8257 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8258 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8259 /* set up input amps for analog loopback */
8260 /* Amp Indices: DAC = 0, mixer = 1 */
8261 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8262 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8263 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8264 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8265 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8266 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8267
8268 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
8269 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
8270 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
8271 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
8272 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
8273 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
8274
8275 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8276 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8277 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8278 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8279 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8280
8281 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8282 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
8283
8284 /* FIXME: use matrix-type input source selection */
8285 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8286 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8287 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8288 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
8289 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
8290 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
8291 /* Input mixer2 */
8292 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8293 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
8294 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
8295 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
8296 /* Input mixer3 */
8297 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8298 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
8299 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008300 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
Kailang Yangdf694da2005-12-05 19:42:22 +01008301
8302 { }
8303};
8304
Kailang Yangccc656c2006-10-17 12:32:26 +02008305static struct hda_verb alc262_hippo_unsol_verbs[] = {
8306 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
8307 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8308 {}
8309};
8310
8311static struct hda_verb alc262_hippo1_unsol_verbs[] = {
8312 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
8313 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
8314 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8315
8316 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
8317 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8318 {}
8319};
8320
Kailang Yang272a5272007-05-14 11:00:38 +02008321static struct hda_verb alc262_sony_unsol_verbs[] = {
8322 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
8323 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8324 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic
8325
8326 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
8327 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8328};
8329
Kailang Yangccc656c2006-10-17 12:32:26 +02008330/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai5b319542007-07-26 11:49:22 +02008331static void alc262_hippo_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02008332{
8333 struct alc_spec *spec = codec->spec;
8334 unsigned int mute;
Takashi Iwai5b319542007-07-26 11:49:22 +02008335 unsigned int present;
Kailang Yangccc656c2006-10-17 12:32:26 +02008336
Takashi Iwai5b319542007-07-26 11:49:22 +02008337 /* need to execute and sync at first */
8338 snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
8339 present = snd_hda_codec_read(codec, 0x15, 0,
8340 AC_VERB_GET_PIN_SENSE, 0);
8341 spec->jack_present = (present & 0x80000000) != 0;
Kailang Yangccc656c2006-10-17 12:32:26 +02008342 if (spec->jack_present) {
8343 /* mute internal speaker */
Takashi Iwai47fd8302007-08-10 17:11:07 +02008344 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8345 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangccc656c2006-10-17 12:32:26 +02008346 } else {
8347 /* unmute internal speaker if necessary */
8348 mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
Takashi Iwai47fd8302007-08-10 17:11:07 +02008349 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8350 HDA_AMP_MUTE, mute);
Kailang Yangccc656c2006-10-17 12:32:26 +02008351 }
8352}
8353
8354/* unsolicited event for HP jack sensing */
8355static void alc262_hippo_unsol_event(struct hda_codec *codec,
8356 unsigned int res)
8357{
8358 if ((res >> 26) != ALC880_HP_EVENT)
8359 return;
Takashi Iwai5b319542007-07-26 11:49:22 +02008360 alc262_hippo_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02008361}
8362
Takashi Iwai5b319542007-07-26 11:49:22 +02008363static void alc262_hippo1_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02008364{
Kailang Yangccc656c2006-10-17 12:32:26 +02008365 unsigned int mute;
Takashi Iwai5b319542007-07-26 11:49:22 +02008366 unsigned int present;
Kailang Yangccc656c2006-10-17 12:32:26 +02008367
Takashi Iwai5b319542007-07-26 11:49:22 +02008368 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
8369 present = snd_hda_codec_read(codec, 0x1b, 0,
8370 AC_VERB_GET_PIN_SENSE, 0);
8371 present = (present & 0x80000000) != 0;
8372 if (present) {
Kailang Yangccc656c2006-10-17 12:32:26 +02008373 /* mute internal speaker */
Takashi Iwai47fd8302007-08-10 17:11:07 +02008374 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8375 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangccc656c2006-10-17 12:32:26 +02008376 } else {
8377 /* unmute internal speaker if necessary */
8378 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
Takashi Iwai47fd8302007-08-10 17:11:07 +02008379 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8380 HDA_AMP_MUTE, mute);
Kailang Yangccc656c2006-10-17 12:32:26 +02008381 }
8382}
8383
8384/* unsolicited event for HP jack sensing */
8385static void alc262_hippo1_unsol_event(struct hda_codec *codec,
8386 unsigned int res)
8387{
8388 if ((res >> 26) != ALC880_HP_EVENT)
8389 return;
Takashi Iwai5b319542007-07-26 11:49:22 +02008390 alc262_hippo1_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02008391}
8392
Takashi Iwai834be882006-03-01 14:16:17 +01008393/*
8394 * fujitsu model
8395 * 0x14 = headphone/spdif-out, 0x15 = internal speaker
8396 */
8397
8398#define ALC_HP_EVENT 0x37
8399
8400static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
8401 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
8402 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8403 {}
8404};
8405
8406static struct hda_input_mux alc262_fujitsu_capture_source = {
Takashi Iwai39d3ed32007-10-12 15:03:48 +02008407 .num_items = 3,
Takashi Iwai834be882006-03-01 14:16:17 +01008408 .items = {
8409 { "Mic", 0x0 },
Takashi Iwai39d3ed32007-10-12 15:03:48 +02008410 { "Int Mic", 0x1 },
Takashi Iwai834be882006-03-01 14:16:17 +01008411 { "CD", 0x4 },
8412 },
8413};
8414
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008415static struct hda_input_mux alc262_HP_capture_source = {
8416 .num_items = 5,
8417 .items = {
8418 { "Mic", 0x0 },
zhejiangaccbe492007-08-31 12:36:05 +02008419 { "Front Mic", 0x1 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008420 { "Line", 0x2 },
8421 { "CD", 0x4 },
8422 { "AUX IN", 0x6 },
8423 },
8424};
8425
zhejiangaccbe492007-08-31 12:36:05 +02008426static struct hda_input_mux alc262_HP_D7000_capture_source = {
8427 .num_items = 4,
8428 .items = {
8429 { "Mic", 0x0 },
8430 { "Front Mic", 0x2 },
8431 { "Line", 0x1 },
8432 { "CD", 0x4 },
8433 },
8434};
8435
Takashi Iwai834be882006-03-01 14:16:17 +01008436/* mute/unmute internal speaker according to the hp jack and mute state */
8437static void alc262_fujitsu_automute(struct hda_codec *codec, int force)
8438{
8439 struct alc_spec *spec = codec->spec;
8440 unsigned int mute;
8441
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008442 if (force || !spec->sense_updated) {
Takashi Iwai834be882006-03-01 14:16:17 +01008443 unsigned int present;
8444 /* need to execute and sync at first */
8445 snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
8446 present = snd_hda_codec_read(codec, 0x14, 0,
8447 AC_VERB_GET_PIN_SENSE, 0);
8448 spec->jack_present = (present & 0x80000000) != 0;
8449 spec->sense_updated = 1;
8450 }
8451 if (spec->jack_present) {
8452 /* mute internal speaker */
Takashi Iwai47fd8302007-08-10 17:11:07 +02008453 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8454 HDA_AMP_MUTE, HDA_AMP_MUTE);
Takashi Iwai834be882006-03-01 14:16:17 +01008455 } else {
8456 /* unmute internal speaker if necessary */
8457 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
Takashi Iwai47fd8302007-08-10 17:11:07 +02008458 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8459 HDA_AMP_MUTE, mute);
Takashi Iwai834be882006-03-01 14:16:17 +01008460 }
8461}
8462
8463/* unsolicited event for HP jack sensing */
8464static void alc262_fujitsu_unsol_event(struct hda_codec *codec,
8465 unsigned int res)
8466{
8467 if ((res >> 26) != ALC_HP_EVENT)
8468 return;
8469 alc262_fujitsu_automute(codec, 1);
8470}
8471
8472/* bind volumes of both NID 0x0c and 0x0d */
Takashi Iwaicca3b372007-08-10 17:12:15 +02008473static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
8474 .ops = &snd_hda_bind_vol,
8475 .values = {
8476 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
8477 HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
8478 0
8479 },
8480};
Takashi Iwai834be882006-03-01 14:16:17 +01008481
8482/* bind hp and internal speaker mute (with plug check) */
8483static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
8484 struct snd_ctl_elem_value *ucontrol)
8485{
8486 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
8487 long *valp = ucontrol->value.integer.value;
8488 int change;
8489
8490 change = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02008491 HDA_AMP_MUTE,
8492 valp[0] ? 0 : HDA_AMP_MUTE);
Takashi Iwai834be882006-03-01 14:16:17 +01008493 change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02008494 HDA_AMP_MUTE,
8495 valp[1] ? 0 : HDA_AMP_MUTE);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02008496 if (change)
8497 alc262_fujitsu_automute(codec, 0);
Takashi Iwai834be882006-03-01 14:16:17 +01008498 return change;
8499}
8500
8501static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02008502 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai834be882006-03-01 14:16:17 +01008503 {
8504 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8505 .name = "Master Playback Switch",
8506 .info = snd_hda_mixer_amp_switch_info,
8507 .get = snd_hda_mixer_amp_switch_get,
8508 .put = alc262_fujitsu_master_sw_put,
8509 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
8510 },
8511 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8512 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8513 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8514 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8515 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai39d3ed32007-10-12 15:03:48 +02008516 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8517 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8518 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +01008519 { } /* end */
8520};
8521
Takashi Iwai304dcaa2006-07-25 14:51:16 +02008522/* additional init verbs for Benq laptops */
8523static struct hda_verb alc262_EAPD_verbs[] = {
8524 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
8525 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
8526 {}
8527};
8528
Kailang Yang83c34212007-07-05 11:43:05 +02008529static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
8530 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8531 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
8532
8533 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
8534 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
8535 {}
8536};
8537
Tobin Davisf651b502007-10-26 12:40:47 +02008538/* Samsung Q1 Ultra Vista model setup */
8539static struct snd_kcontrol_new alc262_ultra_mixer[] = {
8540 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8541 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8542 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8543 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8544 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
8545 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
8546 { } /* end */
8547};
8548
8549static struct hda_verb alc262_ultra_verbs[] = {
8550 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
8551 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8552 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
8553 /* Mic is on Node 0x19 */
8554 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
8555 {0x22, AC_VERB_SET_CONNECT_SEL, 0x01},
8556 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
8557 {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
8558 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
8559 {0x24, AC_VERB_SET_CONNECT_SEL, 0x01},
8560 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
8561 {}
8562};
8563
8564static struct hda_input_mux alc262_ultra_capture_source = {
8565 .num_items = 1,
8566 .items = {
8567 { "Mic", 0x1 },
8568 },
8569};
8570
8571/* mute/unmute internal speaker according to the hp jack and mute state */
8572static void alc262_ultra_automute(struct hda_codec *codec)
8573{
8574 struct alc_spec *spec = codec->spec;
8575 unsigned int mute;
8576 unsigned int present;
8577
8578 /* need to execute and sync at first */
8579 snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
8580 present = snd_hda_codec_read(codec, 0x15, 0,
8581 AC_VERB_GET_PIN_SENSE, 0);
8582 spec->jack_present = (present & 0x80000000) != 0;
8583 if (spec->jack_present) {
8584 /* mute internal speaker */
8585 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8586 HDA_AMP_MUTE, HDA_AMP_MUTE);
8587 } else {
8588 /* unmute internal speaker if necessary */
8589 mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
8590 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8591 HDA_AMP_MUTE, mute);
8592 }
8593}
8594
8595/* unsolicited event for HP jack sensing */
8596static void alc262_ultra_unsol_event(struct hda_codec *codec,
8597 unsigned int res)
8598{
8599 if ((res >> 26) != ALC880_HP_EVENT)
8600 return;
8601 alc262_ultra_automute(codec);
8602}
8603
Kailang Yangdf694da2005-12-05 19:42:22 +01008604/* add playback controls from the parsed DAC table */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008605static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
8606 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +01008607{
8608 hda_nid_t nid;
8609 int err;
8610
8611 spec->multiout.num_dacs = 1; /* only use one dac */
8612 spec->multiout.dac_nids = spec->private_dac_nids;
8613 spec->multiout.dac_nids[0] = 2;
8614
8615 nid = cfg->line_out_pins[0];
8616 if (nid) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008617 err = add_control(spec, ALC_CTL_WIDGET_VOL,
8618 "Front Playback Volume",
8619 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT));
8620 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008621 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008622 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
8623 "Front Playback Switch",
8624 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
8625 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008626 return err;
8627 }
8628
Takashi Iwai82bc9552006-03-21 11:24:42 +01008629 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01008630 if (nid) {
8631 if (nid == 0x16) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008632 err = add_control(spec, ALC_CTL_WIDGET_VOL,
8633 "Speaker Playback Volume",
8634 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
8635 HDA_OUTPUT));
8636 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008637 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008638 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
8639 "Speaker Playback Switch",
8640 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
8641 HDA_OUTPUT));
8642 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008643 return err;
8644 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008645 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
8646 "Speaker Playback Switch",
8647 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
8648 HDA_OUTPUT));
8649 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008650 return err;
8651 }
8652 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02008653 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01008654 if (nid) {
8655 /* spec->multiout.hp_nid = 2; */
8656 if (nid == 0x16) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008657 err = add_control(spec, ALC_CTL_WIDGET_VOL,
8658 "Headphone Playback Volume",
8659 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
8660 HDA_OUTPUT));
8661 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008662 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008663 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
8664 "Headphone Playback Switch",
8665 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
8666 HDA_OUTPUT));
8667 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008668 return err;
8669 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008670 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
8671 "Headphone Playback Switch",
8672 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
8673 HDA_OUTPUT));
8674 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008675 return err;
8676 }
8677 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008678 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01008679}
8680
8681/* identical with ALC880 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008682#define alc262_auto_create_analog_input_ctls \
8683 alc880_auto_create_analog_input_ctls
Kailang Yangdf694da2005-12-05 19:42:22 +01008684
8685/*
8686 * generic initialization of ADC, input mixers and output mixers
8687 */
8688static struct hda_verb alc262_volume_init_verbs[] = {
8689 /*
8690 * Unmute ADC0-2 and set the default input to mic-in
8691 */
8692 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8693 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8694 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8695 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8696 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8697 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8698
Takashi Iwaicb53c622007-08-10 17:21:45 +02008699 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01008700 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008701 * Note: PASD motherboards uses the Line In 2 as the input for
8702 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01008703 */
8704 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02008705 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8706 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8707 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8708 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8709 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01008710
8711 /*
8712 * Set up output mixers (0x0c - 0x0f)
8713 */
8714 /* set vol=0 to output mixers */
8715 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8716 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8717 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8718
8719 /* set up input amps for analog loopback */
8720 /* Amp Indices: DAC = 0, mixer = 1 */
8721 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8722 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8723 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8724 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8725 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8726 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8727
8728 /* FIXME: use matrix-type input source selection */
8729 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8730 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8731 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8732 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
8733 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
8734 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
8735 /* Input mixer2 */
8736 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8737 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
8738 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
8739 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
8740 /* Input mixer3 */
8741 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8742 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
8743 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
8744 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
8745
8746 { }
8747};
8748
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008749static struct hda_verb alc262_HP_BPC_init_verbs[] = {
8750 /*
8751 * Unmute ADC0-2 and set the default input to mic-in
8752 */
8753 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8754 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8755 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8756 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8757 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8758 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8759
Takashi Iwaicb53c622007-08-10 17:21:45 +02008760 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008761 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008762 * Note: PASD motherboards uses the Line In 2 as the input for
8763 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008764 */
8765 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02008766 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8767 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8768 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8769 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8770 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8771 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
8772 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008773
8774 /*
8775 * Set up output mixers (0x0c - 0x0e)
8776 */
8777 /* set vol=0 to output mixers */
8778 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8779 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8780 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8781
8782 /* set up input amps for analog loopback */
8783 /* Amp Indices: DAC = 0, mixer = 1 */
8784 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8785 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8786 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8787 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8788 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8789 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8790
8791 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
8792 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8793 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8794
8795 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8796 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8797
8798 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
8799 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8800
8801 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
8802 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
8803 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
8804 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
8805 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
8806
8807 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
8808 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
8809 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
8810 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
8811 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
8812 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
8813
8814
8815 /* FIXME: use matrix-type input source selection */
8816 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8817 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8818 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8819 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
8820 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
8821 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
8822 /* Input mixer2 */
8823 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8824 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
8825 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
8826 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
8827 /* Input mixer3 */
8828 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8829 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
8830 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
8831 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
8832
8833 { }
8834};
8835
Kailang Yangcd7509a2007-01-26 18:33:17 +01008836static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
8837 /*
8838 * Unmute ADC0-2 and set the default input to mic-in
8839 */
8840 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8841 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8842 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8843 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8844 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8845 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8846
Takashi Iwaicb53c622007-08-10 17:21:45 +02008847 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangcd7509a2007-01-26 18:33:17 +01008848 * mixer widget
8849 * Note: PASD motherboards uses the Line In 2 as the input for front
8850 * panel mic (mic 2)
8851 */
8852 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02008853 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8854 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8855 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8856 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8857 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8858 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
8859 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
8860 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Kailang Yangcd7509a2007-01-26 18:33:17 +01008861 /*
8862 * Set up output mixers (0x0c - 0x0e)
8863 */
8864 /* set vol=0 to output mixers */
8865 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8866 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8867 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8868
8869 /* set up input amps for analog loopback */
8870 /* Amp Indices: DAC = 0, mixer = 1 */
8871 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8872 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8873 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8874 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8875 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8876 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8877
8878
8879 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
8880 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
8881 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
8882 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
8883 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
8884 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
8885 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
8886
8887 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8888 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8889
8890 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
8891 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
8892
8893 /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
8894 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
8895 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
8896 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
8897 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
8898 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
8899
8900 /* FIXME: use matrix-type input source selection */
8901 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8902 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8903 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
8904 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
8905 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
8906 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
8907 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
8908 /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
8909 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
8910 /* Input mixer2 */
8911 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8912 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
8913 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
8914 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
8915 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
8916 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
8917 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
8918 /* Input mixer3 */
8919 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8920 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
8921 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
8922 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
8923 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
8924 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
8925 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
8926
8927 { }
8928};
8929
Takashi Iwaicb53c622007-08-10 17:21:45 +02008930#ifdef CONFIG_SND_HDA_POWER_SAVE
8931#define alc262_loopbacks alc880_loopbacks
8932#endif
8933
Kailang Yangdf694da2005-12-05 19:42:22 +01008934/* pcm configuration: identiacal with ALC880 */
8935#define alc262_pcm_analog_playback alc880_pcm_analog_playback
8936#define alc262_pcm_analog_capture alc880_pcm_analog_capture
8937#define alc262_pcm_digital_playback alc880_pcm_digital_playback
8938#define alc262_pcm_digital_capture alc880_pcm_digital_capture
8939
8940/*
8941 * BIOS auto configuration
8942 */
8943static int alc262_parse_auto_config(struct hda_codec *codec)
8944{
8945 struct alc_spec *spec = codec->spec;
8946 int err;
8947 static hda_nid_t alc262_ignore[] = { 0x1d, 0 };
8948
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008949 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
8950 alc262_ignore);
8951 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008952 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008953 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +01008954 return 0; /* can't find valid BIOS pin config */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008955 err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
8956 if (err < 0)
8957 return err;
8958 err = alc262_auto_create_analog_input_ctls(spec, &spec->autocfg);
8959 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008960 return err;
8961
8962 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
8963
8964 if (spec->autocfg.dig_out_pin)
8965 spec->multiout.dig_out_nid = ALC262_DIGOUT_NID;
8966 if (spec->autocfg.dig_in_pin)
8967 spec->dig_in_nid = ALC262_DIGIN_NID;
8968
8969 if (spec->kctl_alloc)
8970 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
8971
8972 spec->init_verbs[spec->num_init_verbs++] = alc262_volume_init_verbs;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02008973 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +01008974 spec->input_mux = &spec->private_imux;
8975
Takashi Iwai776e1842007-08-29 15:07:11 +02008976 err = alc_auto_add_mic_boost(codec);
8977 if (err < 0)
8978 return err;
8979
Kailang Yangdf694da2005-12-05 19:42:22 +01008980 return 1;
8981}
8982
8983#define alc262_auto_init_multi_out alc882_auto_init_multi_out
8984#define alc262_auto_init_hp_out alc882_auto_init_hp_out
8985#define alc262_auto_init_analog_input alc882_auto_init_analog_input
8986
8987
8988/* init callback for auto-configuration model -- overriding the default init */
Takashi Iwaiae6b8132006-03-03 16:47:17 +01008989static void alc262_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01008990{
Kailang Yangdf694da2005-12-05 19:42:22 +01008991 alc262_auto_init_multi_out(codec);
8992 alc262_auto_init_hp_out(codec);
8993 alc262_auto_init_analog_input(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01008994}
8995
8996/*
8997 * configuration and preset
8998 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008999static const char *alc262_models[ALC262_MODEL_LAST] = {
9000 [ALC262_BASIC] = "basic",
9001 [ALC262_HIPPO] = "hippo",
9002 [ALC262_HIPPO_1] = "hippo_1",
9003 [ALC262_FUJITSU] = "fujitsu",
9004 [ALC262_HP_BPC] = "hp-bpc",
Kailang Yangcd7509a2007-01-26 18:33:17 +01009005 [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
Takashi Iwai61dc35d2007-11-14 12:26:44 +01009006 [ALC262_HP_TC_T5735] = "hp-tc-t5735",
Kailang Yang8c427222008-01-10 13:03:59 +01009007 [ALC262_HP_RP5700] = "hp-rp5700",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009008 [ALC262_BENQ_ED8] = "benq",
Takashi Iwai0f405022007-07-06 12:24:11 +02009009 [ALC262_BENQ_T31] = "benq-t31",
9010 [ALC262_SONY_ASSAMD] = "sony-assamd",
Tobin Davisf651b502007-10-26 12:40:47 +02009011 [ALC262_ULTRA] = "ultra",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009012 [ALC262_AUTO] = "auto",
9013};
9014
9015static struct snd_pci_quirk alc262_cfg_tbl[] = {
9016 SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
9017 SND_PCI_QUIRK(0x103c, 0x12fe, "HP xw9400", ALC262_HP_BPC),
Kailang Yang7d87de22007-06-05 12:17:21 +02009018 SND_PCI_QUIRK(0x103c, 0x12ff, "HP xw4550", ALC262_HP_BPC),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009019 SND_PCI_QUIRK(0x103c, 0x1306, "HP xw8600", ALC262_HP_BPC),
9020 SND_PCI_QUIRK(0x103c, 0x1307, "HP xw6600", ALC262_HP_BPC),
Kailang Yang7d87de22007-06-05 12:17:21 +02009021 SND_PCI_QUIRK(0x103c, 0x1308, "HP xw4600", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +01009022 SND_PCI_QUIRK(0x103c, 0x1309, "HP xw4*00", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +01009023 SND_PCI_QUIRK(0x103c, 0x130a, "HP xw6*00", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +01009024 SND_PCI_QUIRK(0x103c, 0x130b, "HP xw8*00", ALC262_HP_BPC),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009025 SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009026 SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009027 SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009028 SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009029 SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009030 SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009031 SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009032 SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009033 SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
9034 SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
9035 SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009036 SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
9037 ALC262_HP_TC_T5735),
Kailang Yang8c427222008-01-10 13:03:59 +01009038 SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009039 SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009040 SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009041 SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
9042 SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD),
9043 SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009044 SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009045 SND_PCI_QUIRK(0x144d, 0xc032, "Samsung Q1 Ultra", ALC262_ULTRA),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009046 SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
Kailang Yang83c34212007-07-05 11:43:05 +02009047 SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009048 SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
Kailang Yangdf694da2005-12-05 19:42:22 +01009049 {}
9050};
9051
9052static struct alc_config_preset alc262_presets[] = {
9053 [ALC262_BASIC] = {
9054 .mixers = { alc262_base_mixer },
9055 .init_verbs = { alc262_init_verbs },
9056 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9057 .dac_nids = alc262_dac_nids,
9058 .hp_nid = 0x03,
9059 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9060 .channel_mode = alc262_modes,
Takashi Iwaia3bcba32005-12-06 19:05:29 +01009061 .input_mux = &alc262_capture_source,
Kailang Yangdf694da2005-12-05 19:42:22 +01009062 },
Kailang Yangccc656c2006-10-17 12:32:26 +02009063 [ALC262_HIPPO] = {
9064 .mixers = { alc262_base_mixer },
9065 .init_verbs = { alc262_init_verbs, alc262_hippo_unsol_verbs},
9066 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9067 .dac_nids = alc262_dac_nids,
9068 .hp_nid = 0x03,
9069 .dig_out_nid = ALC262_DIGOUT_NID,
9070 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9071 .channel_mode = alc262_modes,
9072 .input_mux = &alc262_capture_source,
9073 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +02009074 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +02009075 },
9076 [ALC262_HIPPO_1] = {
9077 .mixers = { alc262_hippo1_mixer },
9078 .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
9079 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9080 .dac_nids = alc262_dac_nids,
9081 .hp_nid = 0x02,
9082 .dig_out_nid = ALC262_DIGOUT_NID,
9083 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9084 .channel_mode = alc262_modes,
9085 .input_mux = &alc262_capture_source,
9086 .unsol_event = alc262_hippo1_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +02009087 .init_hook = alc262_hippo1_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +02009088 },
Takashi Iwai834be882006-03-01 14:16:17 +01009089 [ALC262_FUJITSU] = {
9090 .mixers = { alc262_fujitsu_mixer },
Takashi Iwai39d3ed32007-10-12 15:03:48 +02009091 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
9092 alc262_fujitsu_unsol_verbs },
Takashi Iwai834be882006-03-01 14:16:17 +01009093 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9094 .dac_nids = alc262_dac_nids,
9095 .hp_nid = 0x03,
9096 .dig_out_nid = ALC262_DIGOUT_NID,
9097 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9098 .channel_mode = alc262_modes,
9099 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01009100 .unsol_event = alc262_fujitsu_unsol_event,
Takashi Iwai834be882006-03-01 14:16:17 +01009101 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009102 [ALC262_HP_BPC] = {
9103 .mixers = { alc262_HP_BPC_mixer },
9104 .init_verbs = { alc262_HP_BPC_init_verbs },
9105 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9106 .dac_nids = alc262_dac_nids,
9107 .hp_nid = 0x03,
9108 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9109 .channel_mode = alc262_modes,
9110 .input_mux = &alc262_HP_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009111 },
Kailang Yangcd7509a2007-01-26 18:33:17 +01009112 [ALC262_HP_BPC_D7000_WF] = {
9113 .mixers = { alc262_HP_BPC_WildWest_mixer },
9114 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
9115 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9116 .dac_nids = alc262_dac_nids,
9117 .hp_nid = 0x03,
9118 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9119 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +02009120 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009121 },
Kailang Yangcd7509a2007-01-26 18:33:17 +01009122 [ALC262_HP_BPC_D7000_WL] = {
9123 .mixers = { alc262_HP_BPC_WildWest_mixer,
9124 alc262_HP_BPC_WildWest_option_mixer },
9125 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
9126 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9127 .dac_nids = alc262_dac_nids,
9128 .hp_nid = 0x03,
9129 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9130 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +02009131 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009132 },
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009133 [ALC262_HP_TC_T5735] = {
9134 .mixers = { alc262_hp_t5735_mixer },
9135 .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
9136 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9137 .dac_nids = alc262_dac_nids,
9138 .hp_nid = 0x03,
9139 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9140 .channel_mode = alc262_modes,
9141 .input_mux = &alc262_capture_source,
9142 .unsol_event = alc262_hp_t5735_unsol_event,
9143 .init_hook = alc262_hp_t5735_init_hook,
Kailang Yang8c427222008-01-10 13:03:59 +01009144 },
9145 [ALC262_HP_RP5700] = {
9146 .mixers = { alc262_hp_rp5700_mixer },
9147 .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
9148 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9149 .dac_nids = alc262_dac_nids,
9150 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9151 .channel_mode = alc262_modes,
9152 .input_mux = &alc262_hp_rp5700_capture_source,
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009153 },
Takashi Iwai304dcaa2006-07-25 14:51:16 +02009154 [ALC262_BENQ_ED8] = {
9155 .mixers = { alc262_base_mixer },
9156 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
9157 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9158 .dac_nids = alc262_dac_nids,
9159 .hp_nid = 0x03,
9160 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9161 .channel_mode = alc262_modes,
9162 .input_mux = &alc262_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009163 },
Kailang Yang272a5272007-05-14 11:00:38 +02009164 [ALC262_SONY_ASSAMD] = {
9165 .mixers = { alc262_sony_mixer },
9166 .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs},
9167 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9168 .dac_nids = alc262_dac_nids,
9169 .hp_nid = 0x02,
9170 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9171 .channel_mode = alc262_modes,
9172 .input_mux = &alc262_capture_source,
9173 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +02009174 .init_hook = alc262_hippo_automute,
Kailang Yang83c34212007-07-05 11:43:05 +02009175 },
9176 [ALC262_BENQ_T31] = {
9177 .mixers = { alc262_benq_t31_mixer },
9178 .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs, alc262_hippo_unsol_verbs },
9179 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9180 .dac_nids = alc262_dac_nids,
9181 .hp_nid = 0x03,
9182 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9183 .channel_mode = alc262_modes,
9184 .input_mux = &alc262_capture_source,
9185 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +02009186 .init_hook = alc262_hippo_automute,
Kailang Yang272a5272007-05-14 11:00:38 +02009187 },
Tobin Davisf651b502007-10-26 12:40:47 +02009188 [ALC262_ULTRA] = {
9189 .mixers = { alc262_ultra_mixer },
9190 .init_verbs = { alc262_init_verbs, alc262_ultra_verbs },
9191 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9192 .dac_nids = alc262_dac_nids,
9193 .hp_nid = 0x03,
9194 .dig_out_nid = ALC262_DIGOUT_NID,
9195 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9196 .channel_mode = alc262_modes,
9197 .input_mux = &alc262_ultra_capture_source,
9198 .unsol_event = alc262_ultra_unsol_event,
9199 .init_hook = alc262_ultra_automute,
9200 },
Kailang Yangdf694da2005-12-05 19:42:22 +01009201};
9202
9203static int patch_alc262(struct hda_codec *codec)
9204{
9205 struct alc_spec *spec;
9206 int board_config;
9207 int err;
9208
Robert P. J. Daydc041e02006-12-19 14:44:15 +01009209 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +01009210 if (spec == NULL)
9211 return -ENOMEM;
9212
9213 codec->spec = spec;
9214#if 0
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009215 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
9216 * under-run
9217 */
Kailang Yangdf694da2005-12-05 19:42:22 +01009218 {
9219 int tmp;
9220 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
9221 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
9222 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
9223 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
9224 }
9225#endif
9226
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009227 board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
9228 alc262_models,
9229 alc262_cfg_tbl);
Kailang Yangcd7509a2007-01-26 18:33:17 +01009230
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009231 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009232 printk(KERN_INFO "hda_codec: Unknown model for ALC262, "
9233 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01009234 board_config = ALC262_AUTO;
9235 }
9236
9237 if (board_config == ALC262_AUTO) {
9238 /* automatic parse from the BIOS config */
9239 err = alc262_parse_auto_config(codec);
9240 if (err < 0) {
9241 alc_free(codec);
9242 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009243 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009244 printk(KERN_INFO
9245 "hda_codec: Cannot set up configuration "
9246 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01009247 board_config = ALC262_BASIC;
9248 }
9249 }
9250
9251 if (board_config != ALC262_AUTO)
9252 setup_preset(spec, &alc262_presets[board_config]);
9253
9254 spec->stream_name_analog = "ALC262 Analog";
9255 spec->stream_analog_playback = &alc262_pcm_analog_playback;
9256 spec->stream_analog_capture = &alc262_pcm_analog_capture;
9257
9258 spec->stream_name_digital = "ALC262 Digital";
9259 spec->stream_digital_playback = &alc262_pcm_digital_playback;
9260 spec->stream_digital_capture = &alc262_pcm_digital_capture;
9261
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009262 if (!spec->adc_nids && spec->input_mux) {
Kailang Yangdf694da2005-12-05 19:42:22 +01009263 /* check whether NID 0x07 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +01009264 unsigned int wcap = get_wcaps(codec, 0x07);
9265
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009266 /* get type */
9267 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Kailang Yangdf694da2005-12-05 19:42:22 +01009268 if (wcap != AC_WID_AUD_IN) {
9269 spec->adc_nids = alc262_adc_nids_alt;
9270 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids_alt);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009271 spec->mixers[spec->num_mixers] =
9272 alc262_capture_alt_mixer;
Kailang Yangdf694da2005-12-05 19:42:22 +01009273 spec->num_mixers++;
9274 } else {
9275 spec->adc_nids = alc262_adc_nids;
9276 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids);
9277 spec->mixers[spec->num_mixers] = alc262_capture_mixer;
9278 spec->num_mixers++;
9279 }
9280 }
9281
Takashi Iwai2134ea42008-01-10 16:53:55 +01009282 spec->vmaster_nid = 0x0c;
9283
Kailang Yangdf694da2005-12-05 19:42:22 +01009284 codec->patch_ops = alc_patch_ops;
9285 if (board_config == ALC262_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01009286 spec->init_hook = alc262_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02009287#ifdef CONFIG_SND_HDA_POWER_SAVE
9288 if (!spec->loopback.amplist)
9289 spec->loopback.amplist = alc262_loopbacks;
9290#endif
Takashi Iwai834be882006-03-01 14:16:17 +01009291
Kailang Yangdf694da2005-12-05 19:42:22 +01009292 return 0;
9293}
9294
Kailang Yangdf694da2005-12-05 19:42:22 +01009295/*
Kailang Yanga361d842007-06-05 12:30:55 +02009296 * ALC268 channel source setting (2 channel)
9297 */
9298#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID
9299#define alc268_modes alc260_modes
9300
9301static hda_nid_t alc268_dac_nids[2] = {
9302 /* front, hp */
9303 0x02, 0x03
9304};
9305
9306static hda_nid_t alc268_adc_nids[2] = {
9307 /* ADC0-1 */
9308 0x08, 0x07
9309};
9310
9311static hda_nid_t alc268_adc_nids_alt[1] = {
9312 /* ADC0 */
9313 0x08
9314};
9315
9316static struct snd_kcontrol_new alc268_base_mixer[] = {
9317 /* output mixer control */
9318 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
9319 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9320 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
9321 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai33bf17a2007-08-21 11:51:42 +02009322 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9323 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
9324 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Kailang Yanga361d842007-06-05 12:30:55 +02009325 { }
9326};
9327
Kailang Yangd1a991a2007-08-15 16:21:59 +02009328static struct hda_verb alc268_eapd_verbs[] = {
9329 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
9330 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
9331 { }
9332};
9333
Takashi Iwaid2738092007-08-16 14:59:45 +02009334/* Toshiba specific */
9335#define alc268_toshiba_automute alc262_hippo_automute
9336
9337static struct hda_verb alc268_toshiba_verbs[] = {
9338 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9339 { } /* end */
9340};
9341
9342/* Acer specific */
Takashi Iwai889c4392007-08-23 18:56:52 +02009343/* bind volumes of both NID 0x02 and 0x03 */
Takashi Iwai6bc96852007-08-17 09:02:12 +02009344static struct hda_bind_ctls alc268_acer_bind_master_vol = {
9345 .ops = &snd_hda_bind_vol,
9346 .values = {
9347 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
9348 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
9349 0
9350 },
9351};
9352
Takashi Iwai889c4392007-08-23 18:56:52 +02009353/* mute/unmute internal speaker according to the hp jack and mute state */
9354static void alc268_acer_automute(struct hda_codec *codec, int force)
9355{
9356 struct alc_spec *spec = codec->spec;
9357 unsigned int mute;
9358
9359 if (force || !spec->sense_updated) {
9360 unsigned int present;
9361 present = snd_hda_codec_read(codec, 0x14, 0,
9362 AC_VERB_GET_PIN_SENSE, 0);
9363 spec->jack_present = (present & 0x80000000) != 0;
9364 spec->sense_updated = 1;
9365 }
9366 if (spec->jack_present)
9367 mute = HDA_AMP_MUTE; /* mute internal speaker */
9368 else /* unmute internal speaker if necessary */
9369 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
9370 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9371 HDA_AMP_MUTE, mute);
9372}
9373
9374
9375/* bind hp and internal speaker mute (with plug check) */
9376static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol,
9377 struct snd_ctl_elem_value *ucontrol)
9378{
9379 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9380 long *valp = ucontrol->value.integer.value;
9381 int change;
9382
9383 change = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
9384 HDA_AMP_MUTE,
9385 valp[0] ? 0 : HDA_AMP_MUTE);
9386 change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
9387 HDA_AMP_MUTE,
9388 valp[1] ? 0 : HDA_AMP_MUTE);
9389 if (change)
9390 alc268_acer_automute(codec, 0);
9391 return change;
9392}
Takashi Iwaid2738092007-08-16 14:59:45 +02009393
9394static struct snd_kcontrol_new alc268_acer_mixer[] = {
9395 /* output mixer control */
9396 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
9397 {
9398 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9399 .name = "Master Playback Switch",
9400 .info = snd_hda_mixer_amp_switch_info,
9401 .get = snd_hda_mixer_amp_switch_get,
9402 .put = alc268_acer_master_sw_put,
9403 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
9404 },
Takashi Iwai33bf17a2007-08-21 11:51:42 +02009405 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9406 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
9407 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Takashi Iwaid2738092007-08-16 14:59:45 +02009408 { }
9409};
9410
9411static struct hda_verb alc268_acer_verbs[] = {
9412 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9413 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9414
9415 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9416 { }
9417};
9418
9419/* unsolicited event for HP jack sensing */
9420static void alc268_toshiba_unsol_event(struct hda_codec *codec,
9421 unsigned int res)
9422{
Takashi Iwai889c4392007-08-23 18:56:52 +02009423 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +02009424 return;
9425 alc268_toshiba_automute(codec);
9426}
9427
9428static void alc268_acer_unsol_event(struct hda_codec *codec,
9429 unsigned int res)
9430{
Takashi Iwai889c4392007-08-23 18:56:52 +02009431 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +02009432 return;
9433 alc268_acer_automute(codec, 1);
9434}
9435
Takashi Iwai889c4392007-08-23 18:56:52 +02009436static void alc268_acer_init_hook(struct hda_codec *codec)
9437{
9438 alc268_acer_automute(codec, 1);
9439}
9440
Kailang Yanga361d842007-06-05 12:30:55 +02009441/*
9442 * generic initialization of ADC, input mixers and output mixers
9443 */
9444static struct hda_verb alc268_base_init_verbs[] = {
9445 /* Unmute DAC0-1 and set vol = 0 */
9446 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9447 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9448 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9449 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9450 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9451 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9452
9453 /*
9454 * Set up output mixers (0x0c - 0x0e)
9455 */
9456 /* set vol=0 to output mixers */
9457 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9458 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9459 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9460 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
9461
9462 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9463 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9464
9465 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
9466 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
9467 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
9468 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9469 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9470 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9471 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9472 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9473
9474 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9475 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9476 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9477 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9478 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9479 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9480 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9481 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9482
Jiang Zhea9b3aa82007-12-20 13:13:13 +01009483 /* Unmute Selector 23h,24h and set the default input to mic-in */
9484
9485 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
9486 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9487 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
9488 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yanga361d842007-06-05 12:30:55 +02009489
Kailang Yanga361d842007-06-05 12:30:55 +02009490 { }
9491};
9492
9493/*
9494 * generic initialization of ADC, input mixers and output mixers
9495 */
9496static struct hda_verb alc268_volume_init_verbs[] = {
9497 /* set output DAC */
9498 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9499 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9500 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9501 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9502
9503 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9504 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9505 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9506 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9507 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9508
9509 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9510 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9511 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9512 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9513 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9514
9515 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9516 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9517 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9518 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9519
9520 /* set PCBEEP vol = 0 */
9521 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, (0xb000 | (0x00 << 8))},
9522
9523 { }
9524};
9525
9526#define alc268_mux_enum_info alc_mux_enum_info
9527#define alc268_mux_enum_get alc_mux_enum_get
9528
9529static int alc268_mux_enum_put(struct snd_kcontrol *kcontrol,
9530 struct snd_ctl_elem_value *ucontrol)
9531{
9532 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9533 struct alc_spec *spec = codec->spec;
Jiang Zhea9b3aa82007-12-20 13:13:13 +01009534
Kailang Yanga361d842007-06-05 12:30:55 +02009535 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
9536 static hda_nid_t capture_mixers[3] = { 0x23, 0x24 };
9537 hda_nid_t nid = capture_mixers[adc_idx];
Kailang Yanga361d842007-06-05 12:30:55 +02009538
Jiang Zhea9b3aa82007-12-20 13:13:13 +01009539 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
9540 nid,
9541 &spec->cur_mux[adc_idx]);
Kailang Yanga361d842007-06-05 12:30:55 +02009542}
9543
9544static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
9545 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
9546 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
9547 {
9548 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9549 /* The multiple "Capture Source" controls confuse alsamixer
9550 * So call somewhat different..
9551 * FIXME: the controls appear in the "playback" view!
9552 */
9553 /* .name = "Capture Source", */
9554 .name = "Input Source",
9555 .count = 1,
9556 .info = alc268_mux_enum_info,
9557 .get = alc268_mux_enum_get,
9558 .put = alc268_mux_enum_put,
9559 },
9560 { } /* end */
9561};
9562
9563static struct snd_kcontrol_new alc268_capture_mixer[] = {
9564 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
9565 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
9566 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
9567 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
9568 {
9569 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9570 /* The multiple "Capture Source" controls confuse alsamixer
9571 * So call somewhat different..
9572 * FIXME: the controls appear in the "playback" view!
9573 */
9574 /* .name = "Capture Source", */
9575 .name = "Input Source",
9576 .count = 2,
9577 .info = alc268_mux_enum_info,
9578 .get = alc268_mux_enum_get,
9579 .put = alc268_mux_enum_put,
9580 },
9581 { } /* end */
9582};
9583
9584static struct hda_input_mux alc268_capture_source = {
9585 .num_items = 4,
9586 .items = {
9587 { "Mic", 0x0 },
9588 { "Front Mic", 0x1 },
9589 { "Line", 0x2 },
9590 { "CD", 0x3 },
9591 },
9592};
9593
Jonathan Woithe86c53bd2008-01-08 12:33:19 +01009594#ifdef CONFIG_SND_DEBUG
9595static struct snd_kcontrol_new alc268_test_mixer[] = {
9596 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
9597 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9598 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
9599 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9600
9601 /* Volume widgets */
9602 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
9603 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
9604 HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
9605 HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
9606 HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
9607 HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
9608 HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
9609 HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
9610 HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
9611 HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
9612 HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
9613 HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
9614 HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
9615 HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),
9616 HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
9617 HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
9618 HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
9619 HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
9620
9621 /* Modes for retasking pin widgets */
9622 ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
9623 ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
9624 ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
9625 ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
9626
9627 /* Controls for GPIO pins, assuming they are configured as outputs */
9628 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
9629 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
9630 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
9631 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
9632
9633 /* Switches to allow the digital SPDIF output pin to be enabled.
9634 * The ALC268 does not have an SPDIF input.
9635 */
9636 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
9637
9638 /* A switch allowing EAPD to be enabled. Some laptops seem to use
9639 * this output to turn on an external amplifier.
9640 */
9641 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
9642 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
9643
9644 { } /* end */
9645};
9646#endif
9647
Kailang Yanga361d842007-06-05 12:30:55 +02009648/* create input playback/capture controls for the given pin */
9649static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
9650 const char *ctlname, int idx)
9651{
9652 char name[32];
9653 int err;
9654
9655 sprintf(name, "%s Playback Volume", ctlname);
9656 if (nid == 0x14) {
9657 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
9658 HDA_COMPOSE_AMP_VAL(0x02, 3, idx,
9659 HDA_OUTPUT));
9660 if (err < 0)
9661 return err;
9662 } else if (nid == 0x15) {
9663 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
9664 HDA_COMPOSE_AMP_VAL(0x03, 3, idx,
9665 HDA_OUTPUT));
9666 if (err < 0)
9667 return err;
9668 } else
9669 return -1;
9670 sprintf(name, "%s Playback Switch", ctlname);
9671 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
9672 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
9673 if (err < 0)
9674 return err;
9675 return 0;
9676}
9677
9678/* add playback controls from the parsed DAC table */
9679static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
9680 const struct auto_pin_cfg *cfg)
9681{
9682 hda_nid_t nid;
9683 int err;
9684
9685 spec->multiout.num_dacs = 2; /* only use one dac */
9686 spec->multiout.dac_nids = spec->private_dac_nids;
9687 spec->multiout.dac_nids[0] = 2;
9688 spec->multiout.dac_nids[1] = 3;
9689
9690 nid = cfg->line_out_pins[0];
9691 if (nid)
9692 alc268_new_analog_output(spec, nid, "Front", 0);
9693
9694 nid = cfg->speaker_pins[0];
9695 if (nid == 0x1d) {
9696 err = add_control(spec, ALC_CTL_WIDGET_VOL,
9697 "Speaker Playback Volume",
9698 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
9699 if (err < 0)
9700 return err;
9701 }
9702 nid = cfg->hp_pins[0];
9703 if (nid)
9704 alc268_new_analog_output(spec, nid, "Headphone", 0);
9705
9706 nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
9707 if (nid == 0x16) {
9708 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9709 "Mono Playback Switch",
9710 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_INPUT));
9711 if (err < 0)
9712 return err;
9713 }
9714 return 0;
9715}
9716
9717/* create playback/capture controls for input pins */
9718static int alc268_auto_create_analog_input_ctls(struct alc_spec *spec,
9719 const struct auto_pin_cfg *cfg)
9720{
9721 struct hda_input_mux *imux = &spec->private_imux;
9722 int i, idx1;
9723
9724 for (i = 0; i < AUTO_PIN_LAST; i++) {
9725 switch(cfg->input_pins[i]) {
9726 case 0x18:
9727 idx1 = 0; /* Mic 1 */
9728 break;
9729 case 0x19:
9730 idx1 = 1; /* Mic 2 */
9731 break;
9732 case 0x1a:
9733 idx1 = 2; /* Line In */
9734 break;
9735 case 0x1c:
9736 idx1 = 3; /* CD */
9737 break;
9738 default:
9739 continue;
9740 }
9741 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
9742 imux->items[imux->num_items].index = idx1;
9743 imux->num_items++;
9744 }
9745 return 0;
9746}
9747
9748static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
9749{
9750 struct alc_spec *spec = codec->spec;
9751 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
9752 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
9753 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
9754 unsigned int dac_vol1, dac_vol2;
9755
9756 if (speaker_nid) {
9757 snd_hda_codec_write(codec, speaker_nid, 0,
9758 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
9759 snd_hda_codec_write(codec, 0x0f, 0,
9760 AC_VERB_SET_AMP_GAIN_MUTE,
9761 AMP_IN_UNMUTE(1));
9762 snd_hda_codec_write(codec, 0x10, 0,
9763 AC_VERB_SET_AMP_GAIN_MUTE,
9764 AMP_IN_UNMUTE(1));
9765 } else {
9766 snd_hda_codec_write(codec, 0x0f, 0,
9767 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
9768 snd_hda_codec_write(codec, 0x10, 0,
9769 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
9770 }
9771
9772 dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */
9773 if (line_nid == 0x14)
9774 dac_vol2 = AMP_OUT_ZERO;
9775 else if (line_nid == 0x15)
9776 dac_vol1 = AMP_OUT_ZERO;
9777 if (hp_nid == 0x14)
9778 dac_vol2 = AMP_OUT_ZERO;
9779 else if (hp_nid == 0x15)
9780 dac_vol1 = AMP_OUT_ZERO;
9781 if (line_nid != 0x16 || hp_nid != 0x16 ||
9782 spec->autocfg.line_out_pins[1] != 0x16 ||
9783 spec->autocfg.line_out_pins[2] != 0x16)
9784 dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
9785
9786 snd_hda_codec_write(codec, 0x02, 0,
9787 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
9788 snd_hda_codec_write(codec, 0x03, 0,
9789 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
9790}
9791
9792/* pcm configuration: identiacal with ALC880 */
9793#define alc268_pcm_analog_playback alc880_pcm_analog_playback
9794#define alc268_pcm_analog_capture alc880_pcm_analog_capture
9795#define alc268_pcm_digital_playback alc880_pcm_digital_playback
9796
9797/*
9798 * BIOS auto configuration
9799 */
9800static int alc268_parse_auto_config(struct hda_codec *codec)
9801{
9802 struct alc_spec *spec = codec->spec;
9803 int err;
9804 static hda_nid_t alc268_ignore[] = { 0 };
9805
9806 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
9807 alc268_ignore);
9808 if (err < 0)
9809 return err;
9810 if (!spec->autocfg.line_outs)
9811 return 0; /* can't find valid BIOS pin config */
9812
9813 err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
9814 if (err < 0)
9815 return err;
9816 err = alc268_auto_create_analog_input_ctls(spec, &spec->autocfg);
9817 if (err < 0)
9818 return err;
9819
9820 spec->multiout.max_channels = 2;
9821
9822 /* digital only support output */
9823 if (spec->autocfg.dig_out_pin)
9824 spec->multiout.dig_out_nid = ALC268_DIGOUT_NID;
9825
9826 if (spec->kctl_alloc)
9827 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
9828
9829 spec->init_verbs[spec->num_init_verbs++] = alc268_volume_init_verbs;
9830 spec->num_mux_defs = 1;
9831 spec->input_mux = &spec->private_imux;
9832
Takashi Iwai776e1842007-08-29 15:07:11 +02009833 err = alc_auto_add_mic_boost(codec);
9834 if (err < 0)
9835 return err;
9836
Kailang Yanga361d842007-06-05 12:30:55 +02009837 return 1;
9838}
9839
9840#define alc268_auto_init_multi_out alc882_auto_init_multi_out
9841#define alc268_auto_init_hp_out alc882_auto_init_hp_out
9842#define alc268_auto_init_analog_input alc882_auto_init_analog_input
9843
9844/* init callback for auto-configuration model -- overriding the default init */
9845static void alc268_auto_init(struct hda_codec *codec)
9846{
9847 alc268_auto_init_multi_out(codec);
9848 alc268_auto_init_hp_out(codec);
9849 alc268_auto_init_mono_speaker_out(codec);
9850 alc268_auto_init_analog_input(codec);
9851}
9852
9853/*
9854 * configuration and preset
9855 */
9856static const char *alc268_models[ALC268_MODEL_LAST] = {
9857 [ALC268_3ST] = "3stack",
Takashi Iwai983f8ae2007-08-15 16:44:04 +02009858 [ALC268_TOSHIBA] = "toshiba",
Takashi Iwaid2738092007-08-16 14:59:45 +02009859 [ALC268_ACER] = "acer",
Jonathan Woithe86c53bd2008-01-08 12:33:19 +01009860#ifdef CONFIG_SND_DEBUG
9861 [ALC268_TEST] = "test",
9862#endif
Kailang Yanga361d842007-06-05 12:30:55 +02009863 [ALC268_AUTO] = "auto",
9864};
9865
9866static struct snd_pci_quirk alc268_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009867 SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
9868 SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
9869 SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA),
Kailang Yanga361d842007-06-05 12:30:55 +02009870 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
Kailang Yangd1a991a2007-08-15 16:21:59 +02009871 SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA),
Takashi Iwai8e7f00f2007-09-07 10:58:58 +02009872 SND_PCI_QUIRK(0x1179, 0xff50, "TOSHIBA A305", ALC268_TOSHIBA),
Takashi Iwaib875bf32007-09-06 15:00:27 +02009873 SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
Kailang Yanga361d842007-06-05 12:30:55 +02009874 {}
9875};
9876
9877static struct alc_config_preset alc268_presets[] = {
9878 [ALC268_3ST] = {
9879 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer },
9880 .init_verbs = { alc268_base_init_verbs },
9881 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
9882 .dac_nids = alc268_dac_nids,
9883 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
9884 .adc_nids = alc268_adc_nids_alt,
9885 .hp_nid = 0x03,
9886 .dig_out_nid = ALC268_DIGOUT_NID,
9887 .num_channel_mode = ARRAY_SIZE(alc268_modes),
9888 .channel_mode = alc268_modes,
9889 .input_mux = &alc268_capture_source,
9890 },
Kailang Yangd1a991a2007-08-15 16:21:59 +02009891 [ALC268_TOSHIBA] = {
9892 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +02009893 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
9894 alc268_toshiba_verbs },
Kailang Yangd1a991a2007-08-15 16:21:59 +02009895 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
9896 .dac_nids = alc268_dac_nids,
9897 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
9898 .adc_nids = alc268_adc_nids_alt,
9899 .hp_nid = 0x03,
9900 .num_channel_mode = ARRAY_SIZE(alc268_modes),
9901 .channel_mode = alc268_modes,
9902 .input_mux = &alc268_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +02009903 .unsol_event = alc268_toshiba_unsol_event,
9904 .init_hook = alc268_toshiba_automute,
9905 },
9906 [ALC268_ACER] = {
9907 .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer },
9908 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
9909 alc268_acer_verbs },
9910 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
9911 .dac_nids = alc268_dac_nids,
9912 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
9913 .adc_nids = alc268_adc_nids_alt,
9914 .hp_nid = 0x02,
9915 .num_channel_mode = ARRAY_SIZE(alc268_modes),
9916 .channel_mode = alc268_modes,
9917 .input_mux = &alc268_capture_source,
9918 .unsol_event = alc268_acer_unsol_event,
Takashi Iwai889c4392007-08-23 18:56:52 +02009919 .init_hook = alc268_acer_init_hook,
Kailang Yangd1a991a2007-08-15 16:21:59 +02009920 },
Jonathan Woithe86c53bd2008-01-08 12:33:19 +01009921#ifdef CONFIG_SND_DEBUG
9922 [ALC268_TEST] = {
9923 .mixers = { alc268_test_mixer, alc268_capture_mixer },
9924 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
9925 alc268_volume_init_verbs },
9926 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
9927 .dac_nids = alc268_dac_nids,
9928 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
9929 .adc_nids = alc268_adc_nids_alt,
9930 .hp_nid = 0x03,
9931 .dig_out_nid = ALC268_DIGOUT_NID,
9932 .num_channel_mode = ARRAY_SIZE(alc268_modes),
9933 .channel_mode = alc268_modes,
9934 .input_mux = &alc268_capture_source,
9935 },
9936#endif
Kailang Yanga361d842007-06-05 12:30:55 +02009937};
9938
9939static int patch_alc268(struct hda_codec *codec)
9940{
9941 struct alc_spec *spec;
9942 int board_config;
9943 int err;
9944
9945 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
9946 if (spec == NULL)
9947 return -ENOMEM;
9948
9949 codec->spec = spec;
9950
9951 board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
9952 alc268_models,
9953 alc268_cfg_tbl);
9954
9955 if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
9956 printk(KERN_INFO "hda_codec: Unknown model for ALC268, "
9957 "trying auto-probe from BIOS...\n");
9958 board_config = ALC268_AUTO;
9959 }
9960
9961 if (board_config == ALC268_AUTO) {
9962 /* automatic parse from the BIOS config */
9963 err = alc268_parse_auto_config(codec);
9964 if (err < 0) {
9965 alc_free(codec);
9966 return err;
9967 } else if (!err) {
9968 printk(KERN_INFO
9969 "hda_codec: Cannot set up configuration "
9970 "from BIOS. Using base mode...\n");
9971 board_config = ALC268_3ST;
9972 }
9973 }
9974
9975 if (board_config != ALC268_AUTO)
9976 setup_preset(spec, &alc268_presets[board_config]);
9977
9978 spec->stream_name_analog = "ALC268 Analog";
9979 spec->stream_analog_playback = &alc268_pcm_analog_playback;
9980 spec->stream_analog_capture = &alc268_pcm_analog_capture;
9981
9982 spec->stream_name_digital = "ALC268 Digital";
9983 spec->stream_digital_playback = &alc268_pcm_digital_playback;
9984
9985 if (board_config == ALC268_AUTO) {
9986 if (!spec->adc_nids && spec->input_mux) {
9987 /* check whether NID 0x07 is valid */
9988 unsigned int wcap = get_wcaps(codec, 0x07);
9989
9990 /* get type */
9991 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
9992 if (wcap != AC_WID_AUD_IN) {
9993 spec->adc_nids = alc268_adc_nids_alt;
9994 spec->num_adc_nids =
9995 ARRAY_SIZE(alc268_adc_nids_alt);
9996 spec->mixers[spec->num_mixers] =
9997 alc268_capture_alt_mixer;
9998 spec->num_mixers++;
9999 } else {
10000 spec->adc_nids = alc268_adc_nids;
10001 spec->num_adc_nids =
10002 ARRAY_SIZE(alc268_adc_nids);
10003 spec->mixers[spec->num_mixers] =
10004 alc268_capture_mixer;
10005 spec->num_mixers++;
10006 }
10007 }
10008 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010010009
10010 spec->vmaster_nid = 0x02;
10011
Kailang Yanga361d842007-06-05 12:30:55 +020010012 codec->patch_ops = alc_patch_ops;
10013 if (board_config == ALC268_AUTO)
10014 spec->init_hook = alc268_auto_init;
10015
10016 return 0;
10017}
10018
10019/*
Kailang Yangf6a92242007-12-13 16:52:54 +010010020 * ALC269 channel source setting (2 channel)
10021 */
10022#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID
10023
10024#define alc269_dac_nids alc260_dac_nids
10025
10026static hda_nid_t alc269_adc_nids[1] = {
10027 /* ADC1 */
10028 0x07,
10029};
10030
10031#define alc269_modes alc260_modes
10032#define alc269_capture_source alc880_lg_lw_capture_source
10033
10034static struct snd_kcontrol_new alc269_base_mixer[] = {
10035 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
10036 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
10037 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
10038 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
10039 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10040 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10041 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10042 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10043 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
10044 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
10045 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10046 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
10047 { } /* end */
10048};
10049
10050/* capture mixer elements */
10051static struct snd_kcontrol_new alc269_capture_mixer[] = {
10052 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
10053 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
10054 {
10055 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10056 /* The multiple "Capture Source" controls confuse alsamixer
10057 * So call somewhat different..
10058 * FIXME: the controls appear in the "playback" view!
10059 */
10060 /* .name = "Capture Source", */
10061 .name = "Input Source",
10062 .count = 1,
10063 .info = alc_mux_enum_info,
10064 .get = alc_mux_enum_get,
10065 .put = alc_mux_enum_put,
10066 },
10067 { } /* end */
10068};
10069
10070/*
10071 * generic initialization of ADC, input mixers and output mixers
10072 */
10073static struct hda_verb alc269_init_verbs[] = {
10074 /*
10075 * Unmute ADC0 and set the default input to mic-in
10076 */
10077 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10078
10079 /* Mute input amps (PCBeep, Line In, Mic 1 & Mic 2) of the
10080 * analog-loopback mixer widget
10081 * Note: PASD motherboards uses the Line In 2 as the input for
10082 * front panel mic (mic 2)
10083 */
10084 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
10085 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10086 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10087 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10088 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10089 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
10090
10091 /*
10092 * Set up output mixers (0x0c - 0x0e)
10093 */
10094 /* set vol=0 to output mixers */
10095 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10096 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10097
10098 /* set up input amps for analog loopback */
10099 /* Amp Indices: DAC = 0, mixer = 1 */
10100 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10101 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10102 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10103 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10104 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10105 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10106
10107 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10108 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10109 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10110 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
10111 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
10112 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
10113 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
10114
10115 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10116 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10117 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10118 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10119 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10120 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10121 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10122
10123 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
10124 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10125
10126 /* FIXME: use matrix-type input source selection */
10127 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
10128 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
10129 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10130 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10131 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10132 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10133
10134 /* set EAPD */
10135 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
10136 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
10137 { }
10138};
10139
10140/* add playback controls from the parsed DAC table */
10141static int alc269_auto_create_multi_out_ctls(struct alc_spec *spec,
10142 const struct auto_pin_cfg *cfg)
10143{
10144 hda_nid_t nid;
10145 int err;
10146
10147 spec->multiout.num_dacs = 1; /* only use one dac */
10148 spec->multiout.dac_nids = spec->private_dac_nids;
10149 spec->multiout.dac_nids[0] = 2;
10150
10151 nid = cfg->line_out_pins[0];
10152 if (nid) {
10153 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10154 "Front Playback Volume",
10155 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT));
10156 if (err < 0)
10157 return err;
10158 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10159 "Front Playback Switch",
10160 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
10161 if (err < 0)
10162 return err;
10163 }
10164
10165 nid = cfg->speaker_pins[0];
10166 if (nid) {
10167 if (!cfg->line_out_pins[0]) {
10168 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10169 "Speaker Playback Volume",
10170 HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
10171 HDA_OUTPUT));
10172 if (err < 0)
10173 return err;
10174 }
10175 if (nid == 0x16) {
10176 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10177 "Speaker Playback Switch",
10178 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
10179 HDA_OUTPUT));
10180 if (err < 0)
10181 return err;
10182 } else {
10183 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10184 "Speaker Playback Switch",
10185 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
10186 HDA_OUTPUT));
10187 if (err < 0)
10188 return err;
10189 }
10190 }
10191 nid = cfg->hp_pins[0];
10192 if (nid) {
10193 /* spec->multiout.hp_nid = 2; */
10194 if (!cfg->line_out_pins[0] && !cfg->speaker_pins[0]) {
10195 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10196 "Headphone Playback Volume",
10197 HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
10198 HDA_OUTPUT));
10199 if (err < 0)
10200 return err;
10201 }
10202 if (nid == 0x16) {
10203 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10204 "Headphone Playback Switch",
10205 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
10206 HDA_OUTPUT));
10207 if (err < 0)
10208 return err;
10209 } else {
10210 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10211 "Headphone Playback Switch",
10212 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
10213 HDA_OUTPUT));
10214 if (err < 0)
10215 return err;
10216 }
10217 }
10218 return 0;
10219}
10220
10221#define alc269_auto_create_analog_input_ctls \
10222 alc880_auto_create_analog_input_ctls
10223
10224#ifdef CONFIG_SND_HDA_POWER_SAVE
10225#define alc269_loopbacks alc880_loopbacks
10226#endif
10227
10228/* pcm configuration: identiacal with ALC880 */
10229#define alc269_pcm_analog_playback alc880_pcm_analog_playback
10230#define alc269_pcm_analog_capture alc880_pcm_analog_capture
10231#define alc269_pcm_digital_playback alc880_pcm_digital_playback
10232#define alc269_pcm_digital_capture alc880_pcm_digital_capture
10233
10234/*
10235 * BIOS auto configuration
10236 */
10237static int alc269_parse_auto_config(struct hda_codec *codec)
10238{
10239 struct alc_spec *spec = codec->spec;
10240 int err;
10241 static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
10242
10243 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
10244 alc269_ignore);
10245 if (err < 0)
10246 return err;
10247
10248 err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
10249 if (err < 0)
10250 return err;
10251 err = alc269_auto_create_analog_input_ctls(spec, &spec->autocfg);
10252 if (err < 0)
10253 return err;
10254
10255 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
10256
10257 if (spec->autocfg.dig_out_pin)
10258 spec->multiout.dig_out_nid = ALC269_DIGOUT_NID;
10259
10260 if (spec->kctl_alloc)
10261 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
10262
10263 spec->init_verbs[spec->num_init_verbs++] = alc269_init_verbs;
10264 spec->num_mux_defs = 1;
10265 spec->input_mux = &spec->private_imux;
10266
10267 err = alc_auto_add_mic_boost(codec);
10268 if (err < 0)
10269 return err;
10270
10271 return 1;
10272}
10273
10274#define alc269_auto_init_multi_out alc882_auto_init_multi_out
10275#define alc269_auto_init_hp_out alc882_auto_init_hp_out
10276#define alc269_auto_init_analog_input alc882_auto_init_analog_input
10277
10278
10279/* init callback for auto-configuration model -- overriding the default init */
10280static void alc269_auto_init(struct hda_codec *codec)
10281{
10282 alc269_auto_init_multi_out(codec);
10283 alc269_auto_init_hp_out(codec);
10284 alc269_auto_init_analog_input(codec);
10285}
10286
10287/*
10288 * configuration and preset
10289 */
10290static const char *alc269_models[ALC269_MODEL_LAST] = {
10291 [ALC269_BASIC] = "basic",
10292};
10293
10294static struct snd_pci_quirk alc269_cfg_tbl[] = {
10295 {}
10296};
10297
10298static struct alc_config_preset alc269_presets[] = {
10299 [ALC269_BASIC] = {
10300 .mixers = { alc269_base_mixer },
10301 .init_verbs = { alc269_init_verbs },
10302 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
10303 .dac_nids = alc269_dac_nids,
10304 .hp_nid = 0x03,
10305 .num_channel_mode = ARRAY_SIZE(alc269_modes),
10306 .channel_mode = alc269_modes,
10307 .input_mux = &alc269_capture_source,
10308 },
10309};
10310
10311static int patch_alc269(struct hda_codec *codec)
10312{
10313 struct alc_spec *spec;
10314 int board_config;
10315 int err;
10316
10317 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
10318 if (spec == NULL)
10319 return -ENOMEM;
10320
10321 codec->spec = spec;
10322
10323 board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
10324 alc269_models,
10325 alc269_cfg_tbl);
10326
10327 if (board_config < 0) {
10328 printk(KERN_INFO "hda_codec: Unknown model for ALC269, "
10329 "trying auto-probe from BIOS...\n");
10330 board_config = ALC269_AUTO;
10331 }
10332
10333 if (board_config == ALC269_AUTO) {
10334 /* automatic parse from the BIOS config */
10335 err = alc269_parse_auto_config(codec);
10336 if (err < 0) {
10337 alc_free(codec);
10338 return err;
10339 } else if (!err) {
10340 printk(KERN_INFO
10341 "hda_codec: Cannot set up configuration "
10342 "from BIOS. Using base mode...\n");
10343 board_config = ALC269_BASIC;
10344 }
10345 }
10346
10347 if (board_config != ALC269_AUTO)
10348 setup_preset(spec, &alc269_presets[board_config]);
10349
10350 spec->stream_name_analog = "ALC269 Analog";
10351 spec->stream_analog_playback = &alc269_pcm_analog_playback;
10352 spec->stream_analog_capture = &alc269_pcm_analog_capture;
10353
10354 spec->stream_name_digital = "ALC269 Digital";
10355 spec->stream_digital_playback = &alc269_pcm_digital_playback;
10356 spec->stream_digital_capture = &alc269_pcm_digital_capture;
10357
10358 spec->adc_nids = alc269_adc_nids;
10359 spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
10360 spec->mixers[spec->num_mixers] = alc269_capture_mixer;
10361 spec->num_mixers++;
10362
10363 codec->patch_ops = alc_patch_ops;
10364 if (board_config == ALC269_AUTO)
10365 spec->init_hook = alc269_auto_init;
10366#ifdef CONFIG_SND_HDA_POWER_SAVE
10367 if (!spec->loopback.amplist)
10368 spec->loopback.amplist = alc269_loopbacks;
10369#endif
10370
10371 return 0;
10372}
10373
10374/*
Kailang Yangdf694da2005-12-05 19:42:22 +010010375 * ALC861 channel source setting (2/6 channel selection for 3-stack)
10376 */
10377
10378/*
10379 * set the path ways for 2 channel output
10380 * need to set the codec line out and mic 1 pin widgets to inputs
10381 */
10382static struct hda_verb alc861_threestack_ch2_init[] = {
10383 /* set pin widget 1Ah (line in) for input */
10384 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010385 /* set pin widget 18h (mic1/2) for input, for mic also enable
10386 * the vref
10387 */
Kailang Yangdf694da2005-12-05 19:42:22 +010010388 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10389
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010390 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
10391#if 0
10392 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
10393 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
10394#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010010395 { } /* end */
10396};
10397/*
10398 * 6ch mode
10399 * need to set the codec line out and mic 1 pin widgets to outputs
10400 */
10401static struct hda_verb alc861_threestack_ch6_init[] = {
10402 /* set pin widget 1Ah (line in) for output (Back Surround)*/
10403 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10404 /* set pin widget 18h (mic1) for output (CLFE)*/
10405 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10406
10407 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010408 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010010409
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010410 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
10411#if 0
10412 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
10413 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
10414#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010010415 { } /* end */
10416};
10417
10418static struct hda_channel_mode alc861_threestack_modes[2] = {
10419 { 2, alc861_threestack_ch2_init },
10420 { 6, alc861_threestack_ch6_init },
10421};
Takashi Iwai22309c32006-08-09 16:57:28 +020010422/* Set mic1 as input and unmute the mixer */
10423static struct hda_verb alc861_uniwill_m31_ch2_init[] = {
10424 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10425 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
10426 { } /* end */
10427};
10428/* Set mic1 as output and mute mixer */
10429static struct hda_verb alc861_uniwill_m31_ch4_init[] = {
10430 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10431 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
10432 { } /* end */
10433};
10434
10435static struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
10436 { 2, alc861_uniwill_m31_ch2_init },
10437 { 4, alc861_uniwill_m31_ch4_init },
10438};
Kailang Yangdf694da2005-12-05 19:42:22 +010010439
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020010440/* Set mic1 and line-in as input and unmute the mixer */
10441static struct hda_verb alc861_asus_ch2_init[] = {
10442 /* set pin widget 1Ah (line in) for input */
10443 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010444 /* set pin widget 18h (mic1/2) for input, for mic also enable
10445 * the vref
10446 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020010447 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10448
10449 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
10450#if 0
10451 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
10452 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
10453#endif
10454 { } /* end */
10455};
10456/* Set mic1 nad line-in as output and mute mixer */
10457static struct hda_verb alc861_asus_ch6_init[] = {
10458 /* set pin widget 1Ah (line in) for output (Back Surround)*/
10459 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10460 /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
10461 /* set pin widget 18h (mic1) for output (CLFE)*/
10462 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10463 /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
10464 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
10465 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
10466
10467 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
10468#if 0
10469 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
10470 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
10471#endif
10472 { } /* end */
10473};
10474
10475static struct hda_channel_mode alc861_asus_modes[2] = {
10476 { 2, alc861_asus_ch2_init },
10477 { 6, alc861_asus_ch6_init },
10478};
10479
Kailang Yangdf694da2005-12-05 19:42:22 +010010480/* patch-ALC861 */
10481
10482static struct snd_kcontrol_new alc861_base_mixer[] = {
10483 /* output mixer control */
10484 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
10485 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
10486 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
10487 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
10488 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
10489
10490 /*Input mixer control */
10491 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
10492 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
10493 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
10494 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
10495 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
10496 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
10497 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
10498 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
10499 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
10500 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010501
Kailang Yangdf694da2005-12-05 19:42:22 +010010502 /* Capture mixer control */
10503 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
10504 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
10505 {
10506 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10507 .name = "Capture Source",
10508 .count = 1,
10509 .info = alc_mux_enum_info,
10510 .get = alc_mux_enum_get,
10511 .put = alc_mux_enum_put,
10512 },
10513 { } /* end */
10514};
10515
10516static struct snd_kcontrol_new alc861_3ST_mixer[] = {
10517 /* output mixer control */
10518 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
10519 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
10520 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
10521 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
10522 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
10523
10524 /* Input mixer control */
10525 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
10526 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
10527 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
10528 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
10529 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
10530 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
10531 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
10532 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
10533 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
10534 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010535
Kailang Yangdf694da2005-12-05 19:42:22 +010010536 /* Capture mixer control */
10537 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
10538 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
10539 {
10540 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10541 .name = "Capture Source",
10542 .count = 1,
10543 .info = alc_mux_enum_info,
10544 .get = alc_mux_enum_get,
10545 .put = alc_mux_enum_put,
10546 },
10547 {
10548 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10549 .name = "Channel Mode",
10550 .info = alc_ch_mode_info,
10551 .get = alc_ch_mode_get,
10552 .put = alc_ch_mode_put,
10553 .private_value = ARRAY_SIZE(alc861_threestack_modes),
10554 },
10555 { } /* end */
Tobin Davisa53d1ae2006-10-17 12:00:28 +020010556};
10557
Takashi Iwaid1d985f2006-11-23 19:27:12 +010010558static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020010559 /* output mixer control */
10560 HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
10561 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
10562 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
10563
10564 /*Capture mixer control */
10565 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
10566 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
10567 {
10568 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10569 .name = "Capture Source",
10570 .count = 1,
10571 .info = alc_mux_enum_info,
10572 .get = alc_mux_enum_get,
10573 .put = alc_mux_enum_put,
10574 },
10575
10576 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010577};
Tobin Davisa53d1ae2006-10-17 12:00:28 +020010578
Takashi Iwai22309c32006-08-09 16:57:28 +020010579static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
10580 /* output mixer control */
10581 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
10582 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
10583 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
10584 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
10585 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
10586
10587 /* Input mixer control */
10588 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
10589 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
10590 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
10591 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
10592 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
10593 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
10594 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
10595 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
10596 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
10597 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010598
Takashi Iwai22309c32006-08-09 16:57:28 +020010599 /* Capture mixer control */
10600 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
10601 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
10602 {
10603 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10604 .name = "Capture Source",
10605 .count = 1,
10606 .info = alc_mux_enum_info,
10607 .get = alc_mux_enum_get,
10608 .put = alc_mux_enum_put,
10609 },
10610 {
10611 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10612 .name = "Channel Mode",
10613 .info = alc_ch_mode_info,
10614 .get = alc_ch_mode_get,
10615 .put = alc_ch_mode_put,
10616 .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
10617 },
10618 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010619};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020010620
10621static struct snd_kcontrol_new alc861_asus_mixer[] = {
10622 /* output mixer control */
10623 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
10624 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
10625 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
10626 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
10627 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
10628
10629 /* Input mixer control */
10630 HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
10631 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10632 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
10633 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
10634 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
10635 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
10636 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
10637 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
10638 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010639 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
10640
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020010641 /* Capture mixer control */
10642 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
10643 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
10644 {
10645 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10646 .name = "Capture Source",
10647 .count = 1,
10648 .info = alc_mux_enum_info,
10649 .get = alc_mux_enum_get,
10650 .put = alc_mux_enum_put,
10651 },
10652 {
10653 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10654 .name = "Channel Mode",
10655 .info = alc_ch_mode_info,
10656 .get = alc_ch_mode_get,
10657 .put = alc_ch_mode_put,
10658 .private_value = ARRAY_SIZE(alc861_asus_modes),
10659 },
10660 { }
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010010661};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020010662
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010010663/* additional mixer */
Takashi Iwaid1d985f2006-11-23 19:27:12 +010010664static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010010665 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
10666 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
10667 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x23, 0x0, HDA_OUTPUT),
10668 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x23, 0x0, HDA_OUTPUT),
10669 { }
10670};
10671
Kailang Yangdf694da2005-12-05 19:42:22 +010010672/*
10673 * generic initialization of ADC, input mixers and output mixers
10674 */
10675static struct hda_verb alc861_base_init_verbs[] = {
10676 /*
10677 * Unmute ADC0 and set the default input to mic-in
10678 */
10679 /* port-A for surround (rear panel) */
10680 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10681 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
10682 /* port-B for mic-in (rear panel) with vref */
10683 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10684 /* port-C for line-in (rear panel) */
10685 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
10686 /* port-D for Front */
10687 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10688 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
10689 /* port-E for HP out (front panel) */
10690 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
10691 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010010692 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010010693 /* port-F for mic-in (front panel) with vref */
10694 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10695 /* port-G for CLFE (rear panel) */
10696 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10697 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
10698 /* port-H for side (rear panel) */
10699 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10700 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
10701 /* CD-in */
10702 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
10703 /* route front mic to ADC1*/
10704 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
10705 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10706
10707 /* Unmute DAC0~3 & spdif out*/
10708 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10709 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10710 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10711 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10712 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10713
10714 /* Unmute Mixer 14 (mic) 1c (Line in)*/
10715 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10716 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10717 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10718 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10719
10720 /* Unmute Stereo Mixer 15 */
10721 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10722 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10723 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010724 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010010725
10726 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10727 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10728 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10729 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10730 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10731 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10732 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10733 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010734 /* hp used DAC 3 (Front) */
10735 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010010736 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
10737
10738 { }
10739};
10740
10741static struct hda_verb alc861_threestack_init_verbs[] = {
10742 /*
10743 * Unmute ADC0 and set the default input to mic-in
10744 */
10745 /* port-A for surround (rear panel) */
10746 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
10747 /* port-B for mic-in (rear panel) with vref */
10748 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10749 /* port-C for line-in (rear panel) */
10750 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
10751 /* port-D for Front */
10752 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10753 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
10754 /* port-E for HP out (front panel) */
10755 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
10756 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010010757 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010010758 /* port-F for mic-in (front panel) with vref */
10759 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10760 /* port-G for CLFE (rear panel) */
10761 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
10762 /* port-H for side (rear panel) */
10763 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
10764 /* CD-in */
10765 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
10766 /* route front mic to ADC1*/
10767 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
10768 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10769 /* Unmute DAC0~3 & spdif out*/
10770 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10771 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10772 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10773 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10774 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10775
10776 /* Unmute Mixer 14 (mic) 1c (Line in)*/
10777 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10778 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10779 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10780 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10781
10782 /* Unmute Stereo Mixer 15 */
10783 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10784 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10785 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010786 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010010787
10788 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10789 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10790 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10791 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10792 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10793 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10794 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10795 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010796 /* hp used DAC 3 (Front) */
10797 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010010798 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
10799 { }
10800};
Takashi Iwai22309c32006-08-09 16:57:28 +020010801
10802static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
10803 /*
10804 * Unmute ADC0 and set the default input to mic-in
10805 */
10806 /* port-A for surround (rear panel) */
10807 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
10808 /* port-B for mic-in (rear panel) with vref */
10809 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10810 /* port-C for line-in (rear panel) */
10811 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
10812 /* port-D for Front */
10813 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10814 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
10815 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010816 /* this has to be set to VREF80 */
10817 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Takashi Iwai22309c32006-08-09 16:57:28 +020010818 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010010819 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai22309c32006-08-09 16:57:28 +020010820 /* port-F for mic-in (front panel) with vref */
10821 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10822 /* port-G for CLFE (rear panel) */
10823 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
10824 /* port-H for side (rear panel) */
10825 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
10826 /* CD-in */
10827 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
10828 /* route front mic to ADC1*/
10829 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
10830 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10831 /* Unmute DAC0~3 & spdif out*/
10832 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10833 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10834 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10835 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10836 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10837
10838 /* Unmute Mixer 14 (mic) 1c (Line in)*/
10839 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10840 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10841 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10842 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10843
10844 /* Unmute Stereo Mixer 15 */
10845 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10846 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10847 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010848 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Takashi Iwai22309c32006-08-09 16:57:28 +020010849
10850 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10851 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10852 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10853 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10854 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10855 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10856 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10857 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010858 /* hp used DAC 3 (Front) */
10859 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Takashi Iwai22309c32006-08-09 16:57:28 +020010860 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
10861 { }
10862};
10863
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020010864static struct hda_verb alc861_asus_init_verbs[] = {
10865 /*
10866 * Unmute ADC0 and set the default input to mic-in
10867 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010868 /* port-A for surround (rear panel)
10869 * according to codec#0 this is the HP jack
10870 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020010871 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
10872 /* route front PCM to HP */
10873 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
10874 /* port-B for mic-in (rear panel) with vref */
10875 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10876 /* port-C for line-in (rear panel) */
10877 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
10878 /* port-D for Front */
10879 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10880 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
10881 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010882 /* this has to be set to VREF80 */
10883 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020010884 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010010885 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020010886 /* port-F for mic-in (front panel) with vref */
10887 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10888 /* port-G for CLFE (rear panel) */
10889 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10890 /* port-H for side (rear panel) */
10891 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10892 /* CD-in */
10893 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
10894 /* route front mic to ADC1*/
10895 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
10896 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10897 /* Unmute DAC0~3 & spdif out*/
10898 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10899 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10900 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10901 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10902 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10903 /* Unmute Mixer 14 (mic) 1c (Line in)*/
10904 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10905 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10906 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10907 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10908
10909 /* Unmute Stereo Mixer 15 */
10910 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10911 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10912 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010913 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020010914
10915 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10916 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10917 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10918 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10919 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10920 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10921 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10922 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010923 /* hp used DAC 3 (Front) */
10924 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020010925 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
10926 { }
10927};
10928
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010010929/* additional init verbs for ASUS laptops */
10930static struct hda_verb alc861_asus_laptop_init_verbs[] = {
10931 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
10932 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
10933 { }
10934};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020010935
Kailang Yangdf694da2005-12-05 19:42:22 +010010936/*
10937 * generic initialization of ADC, input mixers and output mixers
10938 */
10939static struct hda_verb alc861_auto_init_verbs[] = {
10940 /*
10941 * Unmute ADC0 and set the default input to mic-in
10942 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010943 /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */
Kailang Yangdf694da2005-12-05 19:42:22 +010010944 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10945
10946 /* Unmute DAC0~3 & spdif out*/
10947 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10948 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10949 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10950 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10951 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10952
10953 /* Unmute Mixer 14 (mic) 1c (Line in)*/
10954 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10955 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10956 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10957 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10958
10959 /* Unmute Stereo Mixer 15 */
10960 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10961 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10962 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
10963 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
10964
10965 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10966 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10967 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10968 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10969 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10970 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10971 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10972 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10973
10974 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10975 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010976 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
10977 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010010978 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10979 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010980 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
10981 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010010982
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010983 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */
Kailang Yangdf694da2005-12-05 19:42:22 +010010984
10985 { }
10986};
10987
Tobin Davisa53d1ae2006-10-17 12:00:28 +020010988static struct hda_verb alc861_toshiba_init_verbs[] = {
10989 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010990
Tobin Davisa53d1ae2006-10-17 12:00:28 +020010991 { }
10992};
10993
10994/* toggle speaker-output according to the hp-jack state */
10995static void alc861_toshiba_automute(struct hda_codec *codec)
10996{
10997 unsigned int present;
10998
10999 present = snd_hda_codec_read(codec, 0x0f, 0,
11000 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020011001 snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
11002 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
11003 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
11004 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020011005}
11006
11007static void alc861_toshiba_unsol_event(struct hda_codec *codec,
11008 unsigned int res)
11009{
Tobin Davisa53d1ae2006-10-17 12:00:28 +020011010 if ((res >> 26) == ALC880_HP_EVENT)
11011 alc861_toshiba_automute(codec);
11012}
11013
Kailang Yangdf694da2005-12-05 19:42:22 +010011014/* pcm configuration: identiacal with ALC880 */
11015#define alc861_pcm_analog_playback alc880_pcm_analog_playback
11016#define alc861_pcm_analog_capture alc880_pcm_analog_capture
11017#define alc861_pcm_digital_playback alc880_pcm_digital_playback
11018#define alc861_pcm_digital_capture alc880_pcm_digital_capture
11019
11020
11021#define ALC861_DIGOUT_NID 0x07
11022
11023static struct hda_channel_mode alc861_8ch_modes[1] = {
11024 { 8, NULL }
11025};
11026
11027static hda_nid_t alc861_dac_nids[4] = {
11028 /* front, surround, clfe, side */
11029 0x03, 0x06, 0x05, 0x04
11030};
11031
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011032static hda_nid_t alc660_dac_nids[3] = {
11033 /* front, clfe, surround */
11034 0x03, 0x05, 0x06
11035};
11036
Kailang Yangdf694da2005-12-05 19:42:22 +010011037static hda_nid_t alc861_adc_nids[1] = {
11038 /* ADC0-2 */
11039 0x08,
11040};
11041
11042static struct hda_input_mux alc861_capture_source = {
11043 .num_items = 5,
11044 .items = {
11045 { "Mic", 0x0 },
11046 { "Front Mic", 0x3 },
11047 { "Line", 0x1 },
11048 { "CD", 0x4 },
11049 { "Mixer", 0x5 },
11050 },
11051};
11052
11053/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011054static int alc861_auto_fill_dac_nids(struct alc_spec *spec,
11055 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010011056{
11057 int i;
11058 hda_nid_t nid;
11059
11060 spec->multiout.dac_nids = spec->private_dac_nids;
11061 for (i = 0; i < cfg->line_outs; i++) {
11062 nid = cfg->line_out_pins[i];
11063 if (nid) {
11064 if (i >= ARRAY_SIZE(alc861_dac_nids))
11065 continue;
11066 spec->multiout.dac_nids[i] = alc861_dac_nids[i];
11067 }
11068 }
11069 spec->multiout.num_dacs = cfg->line_outs;
11070 return 0;
11071}
11072
11073/* add playback controls from the parsed DAC table */
11074static int alc861_auto_create_multi_out_ctls(struct alc_spec *spec,
11075 const struct auto_pin_cfg *cfg)
11076{
11077 char name[32];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011078 static const char *chname[4] = {
11079 "Front", "Surround", NULL /*CLFE*/, "Side"
11080 };
Kailang Yangdf694da2005-12-05 19:42:22 +010011081 hda_nid_t nid;
11082 int i, idx, err;
11083
11084 for (i = 0; i < cfg->line_outs; i++) {
11085 nid = spec->multiout.dac_nids[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011086 if (!nid)
Kailang Yangdf694da2005-12-05 19:42:22 +010011087 continue;
11088 if (nid == 0x05) {
11089 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011090 err = add_control(spec, ALC_CTL_BIND_MUTE,
11091 "Center Playback Switch",
11092 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
11093 HDA_OUTPUT));
11094 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011095 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011096 err = add_control(spec, ALC_CTL_BIND_MUTE,
11097 "LFE Playback Switch",
11098 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
11099 HDA_OUTPUT));
11100 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011101 return err;
11102 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011103 for (idx = 0; idx < ARRAY_SIZE(alc861_dac_nids) - 1;
11104 idx++)
Kailang Yangdf694da2005-12-05 19:42:22 +010011105 if (nid == alc861_dac_nids[idx])
11106 break;
11107 sprintf(name, "%s Playback Switch", chname[idx]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011108 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
11109 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
11110 HDA_OUTPUT));
11111 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011112 return err;
11113 }
11114 }
11115 return 0;
11116}
11117
11118static int alc861_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin)
11119{
11120 int err;
11121 hda_nid_t nid;
11122
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011123 if (!pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010011124 return 0;
11125
11126 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
11127 nid = 0x03;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011128 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
11129 "Headphone Playback Switch",
11130 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
11131 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011132 return err;
11133 spec->multiout.hp_nid = nid;
11134 }
11135 return 0;
11136}
11137
11138/* create playback/capture controls for input pins */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011139static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec,
11140 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010011141{
Kailang Yangdf694da2005-12-05 19:42:22 +010011142 struct hda_input_mux *imux = &spec->private_imux;
11143 int i, err, idx, idx1;
11144
11145 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011146 switch (cfg->input_pins[i]) {
Kailang Yangdf694da2005-12-05 19:42:22 +010011147 case 0x0c:
11148 idx1 = 1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011149 idx = 2; /* Line In */
Kailang Yangdf694da2005-12-05 19:42:22 +010011150 break;
11151 case 0x0f:
11152 idx1 = 2;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011153 idx = 2; /* Line In */
Kailang Yangdf694da2005-12-05 19:42:22 +010011154 break;
11155 case 0x0d:
11156 idx1 = 0;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011157 idx = 1; /* Mic In */
Kailang Yangdf694da2005-12-05 19:42:22 +010011158 break;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011159 case 0x10:
Kailang Yangdf694da2005-12-05 19:42:22 +010011160 idx1 = 3;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011161 idx = 1; /* Mic In */
Kailang Yangdf694da2005-12-05 19:42:22 +010011162 break;
11163 case 0x11:
11164 idx1 = 4;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011165 idx = 0; /* CD */
Kailang Yangdf694da2005-12-05 19:42:22 +010011166 break;
11167 default:
11168 continue;
11169 }
11170
Takashi Iwai4a471b72005-12-07 13:56:29 +010011171 err = new_analog_input(spec, cfg->input_pins[i],
11172 auto_pin_cfg_labels[i], idx, 0x15);
Kailang Yangdf694da2005-12-05 19:42:22 +010011173 if (err < 0)
11174 return err;
11175
Takashi Iwai4a471b72005-12-07 13:56:29 +010011176 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +010011177 imux->items[imux->num_items].index = idx1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011178 imux->num_items++;
Kailang Yangdf694da2005-12-05 19:42:22 +010011179 }
11180 return 0;
11181}
11182
11183static struct snd_kcontrol_new alc861_capture_mixer[] = {
11184 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
11185 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
11186
11187 {
11188 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11189 /* The multiple "Capture Source" controls confuse alsamixer
11190 * So call somewhat different..
11191 *FIXME: the controls appear in the "playback" view!
11192 */
11193 /* .name = "Capture Source", */
11194 .name = "Input Source",
11195 .count = 1,
11196 .info = alc_mux_enum_info,
11197 .get = alc_mux_enum_get,
11198 .put = alc_mux_enum_put,
11199 },
11200 { } /* end */
11201};
11202
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011203static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
11204 hda_nid_t nid,
Kailang Yangdf694da2005-12-05 19:42:22 +010011205 int pin_type, int dac_idx)
11206{
11207 /* set as output */
11208
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011209 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
11210 pin_type);
11211 snd_hda_codec_write(codec, dac_idx, 0, AC_VERB_SET_AMP_GAIN_MUTE,
11212 AMP_OUT_UNMUTE);
Kailang Yangdf694da2005-12-05 19:42:22 +010011213
11214}
11215
11216static void alc861_auto_init_multi_out(struct hda_codec *codec)
11217{
11218 struct alc_spec *spec = codec->spec;
11219 int i;
11220
Kailang Yangbc9f98a2007-04-12 13:06:07 +020011221 alc_subsystem_id(codec, 0x0e, 0x0f, 0x0b);
Kailang Yangdf694da2005-12-05 19:42:22 +010011222 for (i = 0; i < spec->autocfg.line_outs; i++) {
11223 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020011224 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010011225 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020011226 alc861_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011227 spec->multiout.dac_nids[i]);
Kailang Yangdf694da2005-12-05 19:42:22 +010011228 }
11229}
11230
11231static void alc861_auto_init_hp_out(struct hda_codec *codec)
11232{
11233 struct alc_spec *spec = codec->spec;
11234 hda_nid_t pin;
11235
Takashi Iwaieb06ed82006-09-20 17:10:27 +020011236 pin = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010011237 if (pin) /* connect to front */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011238 alc861_auto_set_output_and_unmute(codec, pin, PIN_HP,
11239 spec->multiout.dac_nids[0]);
Kailang Yangdf694da2005-12-05 19:42:22 +010011240}
11241
11242static void alc861_auto_init_analog_input(struct hda_codec *codec)
11243{
11244 struct alc_spec *spec = codec->spec;
11245 int i;
11246
11247 for (i = 0; i < AUTO_PIN_LAST; i++) {
11248 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011249 if (nid >= 0x0c && nid <= 0x11) {
11250 snd_hda_codec_write(codec, nid, 0,
11251 AC_VERB_SET_PIN_WIDGET_CONTROL,
11252 i <= AUTO_PIN_FRONT_MIC ?
11253 PIN_VREF80 : PIN_IN);
Kailang Yangdf694da2005-12-05 19:42:22 +010011254 }
11255 }
11256}
11257
11258/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011259/* return 1 if successful, 0 if the proper config is not found,
11260 * or a negative error code
11261 */
Kailang Yangdf694da2005-12-05 19:42:22 +010011262static int alc861_parse_auto_config(struct hda_codec *codec)
11263{
11264 struct alc_spec *spec = codec->spec;
11265 int err;
11266 static hda_nid_t alc861_ignore[] = { 0x1d, 0 };
11267
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011268 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
11269 alc861_ignore);
11270 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011271 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011272 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010011273 return 0; /* can't find valid BIOS pin config */
11274
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011275 err = alc861_auto_fill_dac_nids(spec, &spec->autocfg);
11276 if (err < 0)
11277 return err;
11278 err = alc861_auto_create_multi_out_ctls(spec, &spec->autocfg);
11279 if (err < 0)
11280 return err;
11281 err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
11282 if (err < 0)
11283 return err;
11284 err = alc861_auto_create_analog_input_ctls(spec, &spec->autocfg);
11285 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011286 return err;
11287
11288 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
11289
11290 if (spec->autocfg.dig_out_pin)
11291 spec->multiout.dig_out_nid = ALC861_DIGOUT_NID;
11292
11293 if (spec->kctl_alloc)
11294 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
11295
11296 spec->init_verbs[spec->num_init_verbs++] = alc861_auto_init_verbs;
11297
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020011298 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +010011299 spec->input_mux = &spec->private_imux;
11300
11301 spec->adc_nids = alc861_adc_nids;
11302 spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
11303 spec->mixers[spec->num_mixers] = alc861_capture_mixer;
11304 spec->num_mixers++;
11305
11306 return 1;
11307}
11308
Takashi Iwaiae6b8132006-03-03 16:47:17 +010011309/* additional initialization for auto-configuration model */
11310static void alc861_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010011311{
Kailang Yangdf694da2005-12-05 19:42:22 +010011312 alc861_auto_init_multi_out(codec);
11313 alc861_auto_init_hp_out(codec);
11314 alc861_auto_init_analog_input(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010011315}
11316
Takashi Iwaicb53c622007-08-10 17:21:45 +020011317#ifdef CONFIG_SND_HDA_POWER_SAVE
11318static struct hda_amp_list alc861_loopbacks[] = {
11319 { 0x15, HDA_INPUT, 0 },
11320 { 0x15, HDA_INPUT, 1 },
11321 { 0x15, HDA_INPUT, 2 },
11322 { 0x15, HDA_INPUT, 3 },
11323 { } /* end */
11324};
11325#endif
11326
Kailang Yangdf694da2005-12-05 19:42:22 +010011327
11328/*
11329 * configuration and preset
11330 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011331static const char *alc861_models[ALC861_MODEL_LAST] = {
11332 [ALC861_3ST] = "3stack",
11333 [ALC660_3ST] = "3stack-660",
11334 [ALC861_3ST_DIG] = "3stack-dig",
11335 [ALC861_6ST_DIG] = "6stack-dig",
11336 [ALC861_UNIWILL_M31] = "uniwill-m31",
11337 [ALC861_TOSHIBA] = "toshiba",
11338 [ALC861_ASUS] = "asus",
11339 [ALC861_ASUS_LAPTOP] = "asus-laptop",
11340 [ALC861_AUTO] = "auto",
11341};
11342
11343static struct snd_pci_quirk alc861_cfg_tbl[] = {
Takashi Iwai687a47b2007-01-10 11:25:58 +010011344 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011345 SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
11346 SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
11347 SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011348 SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
Kailang Yang83c34212007-07-05 11:43:05 +020011349 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
Tobin Davisad5e7732007-01-08 10:57:32 +010011350 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
Takashi Iwai341d4eb2007-07-09 17:53:18 +020011351 /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
11352 * Any other models that need this preset?
11353 */
11354 /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
Claudio Matsuokaef64adb2007-07-14 00:26:16 +020011355 SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
11356 SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011357 SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
11358 SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
11359 SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
11360 /* FIXME: the below seems conflict */
11361 /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
11362 SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
11363 SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
Kailang Yangdf694da2005-12-05 19:42:22 +010011364 {}
11365};
11366
11367static struct alc_config_preset alc861_presets[] = {
11368 [ALC861_3ST] = {
11369 .mixers = { alc861_3ST_mixer },
11370 .init_verbs = { alc861_threestack_init_verbs },
11371 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
11372 .dac_nids = alc861_dac_nids,
11373 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
11374 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020011375 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010011376 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11377 .adc_nids = alc861_adc_nids,
11378 .input_mux = &alc861_capture_source,
11379 },
11380 [ALC861_3ST_DIG] = {
11381 .mixers = { alc861_base_mixer },
11382 .init_verbs = { alc861_threestack_init_verbs },
11383 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
11384 .dac_nids = alc861_dac_nids,
11385 .dig_out_nid = ALC861_DIGOUT_NID,
11386 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
11387 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020011388 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010011389 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11390 .adc_nids = alc861_adc_nids,
11391 .input_mux = &alc861_capture_source,
11392 },
11393 [ALC861_6ST_DIG] = {
11394 .mixers = { alc861_base_mixer },
11395 .init_verbs = { alc861_base_init_verbs },
11396 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
11397 .dac_nids = alc861_dac_nids,
11398 .dig_out_nid = ALC861_DIGOUT_NID,
11399 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
11400 .channel_mode = alc861_8ch_modes,
11401 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11402 .adc_nids = alc861_adc_nids,
11403 .input_mux = &alc861_capture_source,
11404 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011405 [ALC660_3ST] = {
11406 .mixers = { alc861_3ST_mixer },
11407 .init_verbs = { alc861_threestack_init_verbs },
11408 .num_dacs = ARRAY_SIZE(alc660_dac_nids),
11409 .dac_nids = alc660_dac_nids,
11410 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
11411 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020011412 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011413 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11414 .adc_nids = alc861_adc_nids,
11415 .input_mux = &alc861_capture_source,
11416 },
Takashi Iwai22309c32006-08-09 16:57:28 +020011417 [ALC861_UNIWILL_M31] = {
11418 .mixers = { alc861_uniwill_m31_mixer },
11419 .init_verbs = { alc861_uniwill_m31_init_verbs },
11420 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
11421 .dac_nids = alc861_dac_nids,
11422 .dig_out_nid = ALC861_DIGOUT_NID,
11423 .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
11424 .channel_mode = alc861_uniwill_m31_modes,
11425 .need_dac_fix = 1,
11426 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11427 .adc_nids = alc861_adc_nids,
11428 .input_mux = &alc861_capture_source,
11429 },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020011430 [ALC861_TOSHIBA] = {
11431 .mixers = { alc861_toshiba_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011432 .init_verbs = { alc861_base_init_verbs,
11433 alc861_toshiba_init_verbs },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020011434 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
11435 .dac_nids = alc861_dac_nids,
11436 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
11437 .channel_mode = alc883_3ST_2ch_modes,
11438 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11439 .adc_nids = alc861_adc_nids,
11440 .input_mux = &alc861_capture_source,
11441 .unsol_event = alc861_toshiba_unsol_event,
11442 .init_hook = alc861_toshiba_automute,
11443 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011444 [ALC861_ASUS] = {
11445 .mixers = { alc861_asus_mixer },
11446 .init_verbs = { alc861_asus_init_verbs },
11447 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
11448 .dac_nids = alc861_dac_nids,
11449 .dig_out_nid = ALC861_DIGOUT_NID,
11450 .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
11451 .channel_mode = alc861_asus_modes,
11452 .need_dac_fix = 1,
11453 .hp_nid = 0x06,
11454 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11455 .adc_nids = alc861_adc_nids,
11456 .input_mux = &alc861_capture_source,
11457 },
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010011458 [ALC861_ASUS_LAPTOP] = {
11459 .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
11460 .init_verbs = { alc861_asus_init_verbs,
11461 alc861_asus_laptop_init_verbs },
11462 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
11463 .dac_nids = alc861_dac_nids,
11464 .dig_out_nid = ALC861_DIGOUT_NID,
11465 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
11466 .channel_mode = alc883_3ST_2ch_modes,
11467 .need_dac_fix = 1,
11468 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11469 .adc_nids = alc861_adc_nids,
11470 .input_mux = &alc861_capture_source,
11471 },
11472};
Kailang Yangdf694da2005-12-05 19:42:22 +010011473
11474
11475static int patch_alc861(struct hda_codec *codec)
11476{
11477 struct alc_spec *spec;
11478 int board_config;
11479 int err;
11480
Robert P. J. Daydc041e02006-12-19 14:44:15 +010011481 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010011482 if (spec == NULL)
11483 return -ENOMEM;
11484
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011485 codec->spec = spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010011486
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011487 board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
11488 alc861_models,
11489 alc861_cfg_tbl);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011490
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011491 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011492 printk(KERN_INFO "hda_codec: Unknown model for ALC861, "
11493 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010011494 board_config = ALC861_AUTO;
11495 }
11496
11497 if (board_config == ALC861_AUTO) {
11498 /* automatic parse from the BIOS config */
11499 err = alc861_parse_auto_config(codec);
11500 if (err < 0) {
11501 alc_free(codec);
11502 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011503 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011504 printk(KERN_INFO
11505 "hda_codec: Cannot set up configuration "
11506 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010011507 board_config = ALC861_3ST_DIG;
11508 }
11509 }
11510
11511 if (board_config != ALC861_AUTO)
11512 setup_preset(spec, &alc861_presets[board_config]);
11513
11514 spec->stream_name_analog = "ALC861 Analog";
11515 spec->stream_analog_playback = &alc861_pcm_analog_playback;
11516 spec->stream_analog_capture = &alc861_pcm_analog_capture;
11517
11518 spec->stream_name_digital = "ALC861 Digital";
11519 spec->stream_digital_playback = &alc861_pcm_digital_playback;
11520 spec->stream_digital_capture = &alc861_pcm_digital_capture;
11521
Takashi Iwai2134ea42008-01-10 16:53:55 +010011522 spec->vmaster_nid = 0x03;
11523
Kailang Yangdf694da2005-12-05 19:42:22 +010011524 codec->patch_ops = alc_patch_ops;
11525 if (board_config == ALC861_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010011526 spec->init_hook = alc861_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020011527#ifdef CONFIG_SND_HDA_POWER_SAVE
11528 if (!spec->loopback.amplist)
11529 spec->loopback.amplist = alc861_loopbacks;
11530#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010011531
11532 return 0;
11533}
11534
11535/*
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011536 * ALC861-VD support
11537 *
11538 * Based on ALC882
11539 *
11540 * In addition, an independent DAC
11541 */
11542#define ALC861VD_DIGOUT_NID 0x06
11543
11544static hda_nid_t alc861vd_dac_nids[4] = {
11545 /* front, surr, clfe, side surr */
11546 0x02, 0x03, 0x04, 0x05
11547};
11548
11549/* dac_nids for ALC660vd are in a different order - according to
11550 * Realtek's driver.
11551 * This should probably tesult in a different mixer for 6stack models
11552 * of ALC660vd codecs, but for now there is only 3stack mixer
11553 * - and it is the same as in 861vd.
11554 * adc_nids in ALC660vd are (is) the same as in 861vd
11555 */
11556static hda_nid_t alc660vd_dac_nids[3] = {
11557 /* front, rear, clfe, rear_surr */
11558 0x02, 0x04, 0x03
11559};
11560
11561static hda_nid_t alc861vd_adc_nids[1] = {
11562 /* ADC0 */
11563 0x09,
11564};
11565
11566/* input MUX */
11567/* FIXME: should be a matrix-type input source selection */
11568static struct hda_input_mux alc861vd_capture_source = {
11569 .num_items = 4,
11570 .items = {
11571 { "Mic", 0x0 },
11572 { "Front Mic", 0x1 },
11573 { "Line", 0x2 },
11574 { "CD", 0x4 },
11575 },
11576};
11577
Kailang Yang272a5272007-05-14 11:00:38 +020011578static struct hda_input_mux alc861vd_dallas_capture_source = {
11579 .num_items = 3,
11580 .items = {
11581 { "Front Mic", 0x0 },
11582 { "ATAPI Mic", 0x1 },
11583 { "Line In", 0x5 },
11584 },
11585};
11586
Kailang Yangd1a991a2007-08-15 16:21:59 +020011587static struct hda_input_mux alc861vd_hp_capture_source = {
11588 .num_items = 2,
11589 .items = {
11590 { "Front Mic", 0x0 },
11591 { "ATAPI Mic", 0x1 },
11592 },
11593};
11594
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011595#define alc861vd_mux_enum_info alc_mux_enum_info
11596#define alc861vd_mux_enum_get alc_mux_enum_get
11597
11598static int alc861vd_mux_enum_put(struct snd_kcontrol *kcontrol,
11599 struct snd_ctl_elem_value *ucontrol)
11600{
11601 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11602 struct alc_spec *spec = codec->spec;
11603 const struct hda_input_mux *imux = spec->input_mux;
11604 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
11605 static hda_nid_t capture_mixers[1] = { 0x22 };
11606 hda_nid_t nid = capture_mixers[adc_idx];
11607 unsigned int *cur_val = &spec->cur_mux[adc_idx];
11608 unsigned int i, idx;
11609
11610 idx = ucontrol->value.enumerated.item[0];
11611 if (idx >= imux->num_items)
11612 idx = imux->num_items - 1;
Takashi Iwai82beb8f2007-08-10 17:09:26 +020011613 if (*cur_val == idx)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011614 return 0;
11615 for (i = 0; i < imux->num_items; i++) {
Takashi Iwai47fd8302007-08-10 17:11:07 +020011616 unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
11617 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
11618 imux->items[i].index,
11619 HDA_AMP_MUTE, v);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011620 }
11621 *cur_val = idx;
11622 return 1;
11623}
11624
11625/*
11626 * 2ch mode
11627 */
11628static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
11629 { 2, NULL }
11630};
11631
11632/*
11633 * 6ch mode
11634 */
11635static struct hda_verb alc861vd_6stack_ch6_init[] = {
11636 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
11637 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11638 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11639 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11640 { } /* end */
11641};
11642
11643/*
11644 * 8ch mode
11645 */
11646static struct hda_verb alc861vd_6stack_ch8_init[] = {
11647 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11648 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11649 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11650 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11651 { } /* end */
11652};
11653
11654static struct hda_channel_mode alc861vd_6stack_modes[2] = {
11655 { 6, alc861vd_6stack_ch6_init },
11656 { 8, alc861vd_6stack_ch8_init },
11657};
11658
11659static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
11660 {
11661 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11662 .name = "Channel Mode",
11663 .info = alc_ch_mode_info,
11664 .get = alc_ch_mode_get,
11665 .put = alc_ch_mode_put,
11666 },
11667 { } /* end */
11668};
11669
11670static struct snd_kcontrol_new alc861vd_capture_mixer[] = {
11671 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
11672 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
11673
11674 {
11675 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11676 /* The multiple "Capture Source" controls confuse alsamixer
11677 * So call somewhat different..
11678 *FIXME: the controls appear in the "playback" view!
11679 */
11680 /* .name = "Capture Source", */
11681 .name = "Input Source",
11682 .count = 1,
11683 .info = alc861vd_mux_enum_info,
11684 .get = alc861vd_mux_enum_get,
11685 .put = alc861vd_mux_enum_put,
11686 },
11687 { } /* end */
11688};
11689
11690/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
11691 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
11692 */
11693static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
11694 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11695 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
11696
11697 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
11698 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
11699
11700 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
11701 HDA_OUTPUT),
11702 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
11703 HDA_OUTPUT),
11704 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
11705 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
11706
11707 HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
11708 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
11709
11710 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
11711
11712 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11713 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11714 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11715
11716 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11717 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11718 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
11719
11720 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11721 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11722
11723 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11724 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11725
11726 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
11727 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
11728
11729 { } /* end */
11730};
11731
11732static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
11733 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11734 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
11735
11736 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
11737
11738 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11739 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11740 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11741
11742 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11743 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11744 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
11745
11746 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11747 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11748
11749 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11750 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11751
11752 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
11753 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
11754
11755 { } /* end */
11756};
11757
Kailang Yangbdd148a2007-05-08 15:19:08 +020011758static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
11759 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11760 /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
11761 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11762
11763 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
11764
11765 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11766 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11767 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11768
11769 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11770 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11771 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
11772
11773 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11774 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11775
11776 { } /* end */
11777};
11778
Kailang Yang272a5272007-05-14 11:00:38 +020011779/* Pin assignment: Front=0x14, HP = 0x15,
11780 * Front Mic=0x18, ATAPI Mic = 0x19, Line In = 0x1d
11781 */
11782static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
11783 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11784 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
11785 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
11786 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
11787 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11788 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11789 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11790 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
11791 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x05, HDA_INPUT),
11792 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020011793 { } /* end */
11794};
11795
Kailang Yangd1a991a2007-08-15 16:21:59 +020011796/* Pin assignment: Speaker=0x14, Line-out = 0x15,
11797 * Front Mic=0x18, ATAPI Mic = 0x19,
11798 */
11799static struct snd_kcontrol_new alc861vd_hp_mixer[] = {
11800 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11801 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
11802 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
11803 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
11804 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11805 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11806 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11807 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
11808
11809 { } /* end */
11810};
11811
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011812/*
11813 * generic initialization of ADC, input mixers and output mixers
11814 */
11815static struct hda_verb alc861vd_volume_init_verbs[] = {
11816 /*
11817 * Unmute ADC0 and set the default input to mic-in
11818 */
11819 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
11820 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11821
11822 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
11823 * the analog-loopback mixer widget
11824 */
11825 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020011826 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11827 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11828 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11829 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11830 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011831
11832 /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yangbdd148a2007-05-08 15:19:08 +020011833 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11834 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11835 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011836 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011837
11838 /*
11839 * Set up output mixers (0x02 - 0x05)
11840 */
11841 /* set vol=0 to output mixers */
11842 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11843 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11844 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11845 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11846
11847 /* set up input amps for analog loopback */
11848 /* Amp Indices: DAC = 0, mixer = 1 */
11849 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11850 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11851 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11852 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11853 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11854 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11855 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11856 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11857
11858 { }
11859};
11860
11861/*
11862 * 3-stack pin configuration:
11863 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
11864 */
11865static struct hda_verb alc861vd_3stack_init_verbs[] = {
11866 /*
11867 * Set pin mode and muting
11868 */
11869 /* set front pin widgets 0x14 for output */
11870 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11871 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11872 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
11873
11874 /* Mic (rear) pin: input vref at 80% */
11875 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
11876 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11877 /* Front Mic pin: input vref at 80% */
11878 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
11879 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11880 /* Line In pin: input */
11881 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11882 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11883 /* Line-2 In: Headphone output (output 0 - 0x0c) */
11884 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11885 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11886 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11887 /* CD pin widget for input */
11888 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11889
11890 { }
11891};
11892
11893/*
11894 * 6-stack pin configuration:
11895 */
11896static struct hda_verb alc861vd_6stack_init_verbs[] = {
11897 /*
11898 * Set pin mode and muting
11899 */
11900 /* set front pin widgets 0x14 for output */
11901 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11902 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11903 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
11904
11905 /* Rear Pin: output 1 (0x0d) */
11906 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11907 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11908 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
11909 /* CLFE Pin: output 2 (0x0e) */
11910 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11911 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11912 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
11913 /* Side Pin: output 3 (0x0f) */
11914 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11915 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11916 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
11917
11918 /* Mic (rear) pin: input vref at 80% */
11919 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
11920 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11921 /* Front Mic pin: input vref at 80% */
11922 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
11923 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11924 /* Line In pin: input */
11925 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11926 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11927 /* Line-2 In: Headphone output (output 0 - 0x0c) */
11928 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11929 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11930 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11931 /* CD pin widget for input */
11932 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11933
11934 { }
11935};
11936
Kailang Yangbdd148a2007-05-08 15:19:08 +020011937static struct hda_verb alc861vd_eapd_verbs[] = {
11938 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
11939 { }
11940};
11941
11942static struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
11943 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11944 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11945 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
11946 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11947 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11948 {}
11949};
11950
11951/* toggle speaker-output according to the hp-jack state */
11952static void alc861vd_lenovo_hp_automute(struct hda_codec *codec)
11953{
11954 unsigned int present;
11955 unsigned char bits;
11956
11957 present = snd_hda_codec_read(codec, 0x1b, 0,
11958 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020011959 bits = present ? HDA_AMP_MUTE : 0;
11960 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11961 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020011962}
11963
11964static void alc861vd_lenovo_mic_automute(struct hda_codec *codec)
11965{
11966 unsigned int present;
11967 unsigned char bits;
11968
11969 present = snd_hda_codec_read(codec, 0x18, 0,
11970 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020011971 bits = present ? HDA_AMP_MUTE : 0;
11972 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
11973 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020011974}
11975
11976static void alc861vd_lenovo_automute(struct hda_codec *codec)
11977{
11978 alc861vd_lenovo_hp_automute(codec);
11979 alc861vd_lenovo_mic_automute(codec);
11980}
11981
11982static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
11983 unsigned int res)
11984{
11985 switch (res >> 26) {
11986 case ALC880_HP_EVENT:
11987 alc861vd_lenovo_hp_automute(codec);
11988 break;
11989 case ALC880_MIC_EVENT:
11990 alc861vd_lenovo_mic_automute(codec);
11991 break;
11992 }
11993}
11994
Kailang Yang272a5272007-05-14 11:00:38 +020011995static struct hda_verb alc861vd_dallas_verbs[] = {
11996 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11997 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11998 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11999 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12000
12001 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12002 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12003 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12004 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12005 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12006 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12007 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12008 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12009
12010 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12011 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12012 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12013 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12014 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12015 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12016 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12017 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12018
12019 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
12020 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12021 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
12022 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12023 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12024 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12025 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12026 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12027
12028 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12029 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12030 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12031 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12032
12033 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12034 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12035 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12036
12037 { } /* end */
12038};
12039
12040/* toggle speaker-output according to the hp-jack state */
12041static void alc861vd_dallas_automute(struct hda_codec *codec)
12042{
12043 unsigned int present;
12044
12045 present = snd_hda_codec_read(codec, 0x15, 0,
12046 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020012047 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
12048 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +020012049}
12050
12051static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int res)
12052{
12053 if ((res >> 26) == ALC880_HP_EVENT)
12054 alc861vd_dallas_automute(codec);
12055}
12056
Takashi Iwaicb53c622007-08-10 17:21:45 +020012057#ifdef CONFIG_SND_HDA_POWER_SAVE
12058#define alc861vd_loopbacks alc880_loopbacks
12059#endif
12060
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012061/* pcm configuration: identiacal with ALC880 */
12062#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback
12063#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture
12064#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback
12065#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture
12066
12067/*
12068 * configuration and preset
12069 */
12070static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
12071 [ALC660VD_3ST] = "3stack-660",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020012072 [ALC660VD_3ST_DIG] = "3stack-660-digout",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012073 [ALC861VD_3ST] = "3stack",
12074 [ALC861VD_3ST_DIG] = "3stack-digout",
12075 [ALC861VD_6ST_DIG] = "6stack-digout",
Kailang Yangbdd148a2007-05-08 15:19:08 +020012076 [ALC861VD_LENOVO] = "lenovo",
Kailang Yang272a5272007-05-14 11:00:38 +020012077 [ALC861VD_DALLAS] = "dallas",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020012078 [ALC861VD_HP] = "hp",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012079 [ALC861VD_AUTO] = "auto",
12080};
12081
12082static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012083 SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
12084 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
Takashi Iwai07e038b2007-02-15 18:23:41 +010012085 SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012086 SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),
Mike Crash6963f842007-06-25 12:12:51 +020012087 SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012088 SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012089 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai38baf5a2007-08-16 17:52:43 +020012090 /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
Kailang Yang272a5272007-05-14 11:00:38 +020012091 SND_PCI_QUIRK(0x1179, 0xff01, "DALLAS", ALC861VD_DALLAS),
Takashi Iwai542d7c62007-08-16 18:57:30 +020012092 SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
Takashi Iwai39c5d412007-08-15 16:24:17 +020012093 SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012094 SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO),
12095 SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO),
Tobin Davis625dc0b2007-07-30 21:42:10 +020012096 SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012097 {}
12098};
12099
12100static struct alc_config_preset alc861vd_presets[] = {
12101 [ALC660VD_3ST] = {
12102 .mixers = { alc861vd_3st_mixer },
12103 .init_verbs = { alc861vd_volume_init_verbs,
12104 alc861vd_3stack_init_verbs },
12105 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
12106 .dac_nids = alc660vd_dac_nids,
12107 .num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids),
12108 .adc_nids = alc861vd_adc_nids,
12109 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12110 .channel_mode = alc861vd_3stack_2ch_modes,
12111 .input_mux = &alc861vd_capture_source,
12112 },
Mike Crash6963f842007-06-25 12:12:51 +020012113 [ALC660VD_3ST_DIG] = {
12114 .mixers = { alc861vd_3st_mixer },
12115 .init_verbs = { alc861vd_volume_init_verbs,
12116 alc861vd_3stack_init_verbs },
12117 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
12118 .dac_nids = alc660vd_dac_nids,
12119 .dig_out_nid = ALC861VD_DIGOUT_NID,
12120 .num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids),
12121 .adc_nids = alc861vd_adc_nids,
12122 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12123 .channel_mode = alc861vd_3stack_2ch_modes,
12124 .input_mux = &alc861vd_capture_source,
12125 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012126 [ALC861VD_3ST] = {
12127 .mixers = { alc861vd_3st_mixer },
12128 .init_verbs = { alc861vd_volume_init_verbs,
12129 alc861vd_3stack_init_verbs },
12130 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
12131 .dac_nids = alc861vd_dac_nids,
12132 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12133 .channel_mode = alc861vd_3stack_2ch_modes,
12134 .input_mux = &alc861vd_capture_source,
12135 },
12136 [ALC861VD_3ST_DIG] = {
12137 .mixers = { alc861vd_3st_mixer },
12138 .init_verbs = { alc861vd_volume_init_verbs,
12139 alc861vd_3stack_init_verbs },
12140 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
12141 .dac_nids = alc861vd_dac_nids,
12142 .dig_out_nid = ALC861VD_DIGOUT_NID,
12143 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12144 .channel_mode = alc861vd_3stack_2ch_modes,
12145 .input_mux = &alc861vd_capture_source,
12146 },
12147 [ALC861VD_6ST_DIG] = {
12148 .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
12149 .init_verbs = { alc861vd_volume_init_verbs,
12150 alc861vd_6stack_init_verbs },
12151 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
12152 .dac_nids = alc861vd_dac_nids,
12153 .dig_out_nid = ALC861VD_DIGOUT_NID,
12154 .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
12155 .channel_mode = alc861vd_6stack_modes,
12156 .input_mux = &alc861vd_capture_source,
12157 },
Kailang Yangbdd148a2007-05-08 15:19:08 +020012158 [ALC861VD_LENOVO] = {
12159 .mixers = { alc861vd_lenovo_mixer },
12160 .init_verbs = { alc861vd_volume_init_verbs,
12161 alc861vd_3stack_init_verbs,
12162 alc861vd_eapd_verbs,
12163 alc861vd_lenovo_unsol_verbs },
12164 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
12165 .dac_nids = alc660vd_dac_nids,
12166 .num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids),
12167 .adc_nids = alc861vd_adc_nids,
12168 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12169 .channel_mode = alc861vd_3stack_2ch_modes,
12170 .input_mux = &alc861vd_capture_source,
12171 .unsol_event = alc861vd_lenovo_unsol_event,
12172 .init_hook = alc861vd_lenovo_automute,
12173 },
Kailang Yang272a5272007-05-14 11:00:38 +020012174 [ALC861VD_DALLAS] = {
12175 .mixers = { alc861vd_dallas_mixer },
12176 .init_verbs = { alc861vd_dallas_verbs },
12177 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
12178 .dac_nids = alc861vd_dac_nids,
12179 .num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids),
12180 .adc_nids = alc861vd_adc_nids,
12181 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12182 .channel_mode = alc861vd_3stack_2ch_modes,
12183 .input_mux = &alc861vd_dallas_capture_source,
12184 .unsol_event = alc861vd_dallas_unsol_event,
12185 .init_hook = alc861vd_dallas_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +020012186 },
12187 [ALC861VD_HP] = {
12188 .mixers = { alc861vd_hp_mixer },
12189 .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
12190 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
12191 .dac_nids = alc861vd_dac_nids,
12192 .num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids),
12193 .dig_out_nid = ALC861VD_DIGOUT_NID,
12194 .adc_nids = alc861vd_adc_nids,
12195 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12196 .channel_mode = alc861vd_3stack_2ch_modes,
12197 .input_mux = &alc861vd_hp_capture_source,
12198 .unsol_event = alc861vd_dallas_unsol_event,
12199 .init_hook = alc861vd_dallas_automute,
12200 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012201};
12202
12203/*
12204 * BIOS auto configuration
12205 */
12206static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
12207 hda_nid_t nid, int pin_type, int dac_idx)
12208{
12209 /* set as output */
12210 snd_hda_codec_write(codec, nid, 0,
12211 AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
12212 snd_hda_codec_write(codec, nid, 0,
12213 AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
12214}
12215
12216static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
12217{
12218 struct alc_spec *spec = codec->spec;
12219 int i;
12220
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012221 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012222 for (i = 0; i <= HDA_SIDE; i++) {
12223 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020012224 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012225 if (nid)
12226 alc861vd_auto_set_output_and_unmute(codec, nid,
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020012227 pin_type, i);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012228 }
12229}
12230
12231
12232static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
12233{
12234 struct alc_spec *spec = codec->spec;
12235 hda_nid_t pin;
12236
12237 pin = spec->autocfg.hp_pins[0];
12238 if (pin) /* connect to front and use dac 0 */
12239 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
12240}
12241
12242#define alc861vd_is_input_pin(nid) alc880_is_input_pin(nid)
12243#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID
12244
12245static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
12246{
12247 struct alc_spec *spec = codec->spec;
12248 int i;
12249
12250 for (i = 0; i < AUTO_PIN_LAST; i++) {
12251 hda_nid_t nid = spec->autocfg.input_pins[i];
12252 if (alc861vd_is_input_pin(nid)) {
12253 snd_hda_codec_write(codec, nid, 0,
12254 AC_VERB_SET_PIN_WIDGET_CONTROL,
12255 i <= AUTO_PIN_FRONT_MIC ?
12256 PIN_VREF80 : PIN_IN);
12257 if (nid != ALC861VD_PIN_CD_NID)
12258 snd_hda_codec_write(codec, nid, 0,
12259 AC_VERB_SET_AMP_GAIN_MUTE,
12260 AMP_OUT_MUTE);
12261 }
12262 }
12263}
12264
12265#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
12266#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
12267
12268/* add playback controls from the parsed DAC table */
12269/* Based on ALC880 version. But ALC861VD has separate,
12270 * different NIDs for mute/unmute switch and volume control */
12271static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
12272 const struct auto_pin_cfg *cfg)
12273{
12274 char name[32];
12275 static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
12276 hda_nid_t nid_v, nid_s;
12277 int i, err;
12278
12279 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012280 if (!spec->multiout.dac_nids[i])
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012281 continue;
12282 nid_v = alc861vd_idx_to_mixer_vol(
12283 alc880_dac_to_idx(
12284 spec->multiout.dac_nids[i]));
12285 nid_s = alc861vd_idx_to_mixer_switch(
12286 alc880_dac_to_idx(
12287 spec->multiout.dac_nids[i]));
12288
12289 if (i == 2) {
12290 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012291 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12292 "Center Playback Volume",
12293 HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
12294 HDA_OUTPUT));
12295 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012296 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012297 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12298 "LFE Playback Volume",
12299 HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
12300 HDA_OUTPUT));
12301 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012302 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012303 err = add_control(spec, ALC_CTL_BIND_MUTE,
12304 "Center Playback Switch",
12305 HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
12306 HDA_INPUT));
12307 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012308 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012309 err = add_control(spec, ALC_CTL_BIND_MUTE,
12310 "LFE Playback Switch",
12311 HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
12312 HDA_INPUT));
12313 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012314 return err;
12315 } else {
12316 sprintf(name, "%s Playback Volume", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012317 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
12318 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
12319 HDA_OUTPUT));
12320 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012321 return err;
12322 sprintf(name, "%s Playback Switch", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012323 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
Kailang Yangbdd148a2007-05-08 15:19:08 +020012324 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012325 HDA_INPUT));
12326 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012327 return err;
12328 }
12329 }
12330 return 0;
12331}
12332
12333/* add playback controls for speaker and HP outputs */
12334/* Based on ALC880 version. But ALC861VD has separate,
12335 * different NIDs for mute/unmute switch and volume control */
12336static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
12337 hda_nid_t pin, const char *pfx)
12338{
12339 hda_nid_t nid_v, nid_s;
12340 int err;
12341 char name[32];
12342
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012343 if (!pin)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012344 return 0;
12345
12346 if (alc880_is_fixed_pin(pin)) {
12347 nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
12348 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012349 if (!spec->multiout.hp_nid)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012350 spec->multiout.hp_nid = nid_v;
12351 else
12352 spec->multiout.extra_out_nid[0] = nid_v;
12353 /* control HP volume/switch on the output mixer amp */
12354 nid_v = alc861vd_idx_to_mixer_vol(
12355 alc880_fixed_pin_idx(pin));
12356 nid_s = alc861vd_idx_to_mixer_switch(
12357 alc880_fixed_pin_idx(pin));
12358
12359 sprintf(name, "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012360 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
12361 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
12362 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012363 return err;
12364 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012365 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
12366 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
12367 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012368 return err;
12369 } else if (alc880_is_multi_pin(pin)) {
12370 /* set manual connection */
12371 /* we have only a switch on HP-out PIN */
12372 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012373 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
12374 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
12375 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012376 return err;
12377 }
12378 return 0;
12379}
12380
12381/* parse the BIOS configuration and set up the alc_spec
12382 * return 1 if successful, 0 if the proper config is not found,
12383 * or a negative error code
12384 * Based on ALC880 version - had to change it to override
12385 * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
12386static int alc861vd_parse_auto_config(struct hda_codec *codec)
12387{
12388 struct alc_spec *spec = codec->spec;
12389 int err;
12390 static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
12391
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012392 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
12393 alc861vd_ignore);
12394 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012395 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012396 if (!spec->autocfg.line_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012397 return 0; /* can't find valid BIOS pin config */
12398
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012399 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
12400 if (err < 0)
12401 return err;
12402 err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
12403 if (err < 0)
12404 return err;
12405 err = alc861vd_auto_create_extra_out(spec,
12406 spec->autocfg.speaker_pins[0],
12407 "Speaker");
12408 if (err < 0)
12409 return err;
12410 err = alc861vd_auto_create_extra_out(spec,
12411 spec->autocfg.hp_pins[0],
12412 "Headphone");
12413 if (err < 0)
12414 return err;
12415 err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg);
12416 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012417 return err;
12418
12419 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
12420
12421 if (spec->autocfg.dig_out_pin)
12422 spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID;
12423
12424 if (spec->kctl_alloc)
12425 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
12426
12427 spec->init_verbs[spec->num_init_verbs++]
12428 = alc861vd_volume_init_verbs;
12429
12430 spec->num_mux_defs = 1;
12431 spec->input_mux = &spec->private_imux;
12432
Takashi Iwai776e1842007-08-29 15:07:11 +020012433 err = alc_auto_add_mic_boost(codec);
12434 if (err < 0)
12435 return err;
12436
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012437 return 1;
12438}
12439
12440/* additional initialization for auto-configuration model */
12441static void alc861vd_auto_init(struct hda_codec *codec)
12442{
12443 alc861vd_auto_init_multi_out(codec);
12444 alc861vd_auto_init_hp_out(codec);
12445 alc861vd_auto_init_analog_input(codec);
12446}
12447
12448static int patch_alc861vd(struct hda_codec *codec)
12449{
12450 struct alc_spec *spec;
12451 int err, board_config;
12452
12453 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
12454 if (spec == NULL)
12455 return -ENOMEM;
12456
12457 codec->spec = spec;
12458
12459 board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
12460 alc861vd_models,
12461 alc861vd_cfg_tbl);
12462
12463 if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
12464 printk(KERN_INFO "hda_codec: Unknown model for ALC660VD/"
12465 "ALC861VD, trying auto-probe from BIOS...\n");
12466 board_config = ALC861VD_AUTO;
12467 }
12468
12469 if (board_config == ALC861VD_AUTO) {
12470 /* automatic parse from the BIOS config */
12471 err = alc861vd_parse_auto_config(codec);
12472 if (err < 0) {
12473 alc_free(codec);
12474 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012475 } else if (!err) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012476 printk(KERN_INFO
12477 "hda_codec: Cannot set up configuration "
12478 "from BIOS. Using base mode...\n");
12479 board_config = ALC861VD_3ST;
12480 }
12481 }
12482
12483 if (board_config != ALC861VD_AUTO)
12484 setup_preset(spec, &alc861vd_presets[board_config]);
12485
12486 spec->stream_name_analog = "ALC861VD Analog";
12487 spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
12488 spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
12489
12490 spec->stream_name_digital = "ALC861VD Digital";
12491 spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
12492 spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
12493
12494 spec->adc_nids = alc861vd_adc_nids;
12495 spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
12496
12497 spec->mixers[spec->num_mixers] = alc861vd_capture_mixer;
12498 spec->num_mixers++;
12499
Takashi Iwai2134ea42008-01-10 16:53:55 +010012500 spec->vmaster_nid = 0x02;
12501
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012502 codec->patch_ops = alc_patch_ops;
12503
12504 if (board_config == ALC861VD_AUTO)
12505 spec->init_hook = alc861vd_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020012506#ifdef CONFIG_SND_HDA_POWER_SAVE
12507 if (!spec->loopback.amplist)
12508 spec->loopback.amplist = alc861vd_loopbacks;
12509#endif
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012510
12511 return 0;
12512}
12513
12514/*
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012515 * ALC662 support
12516 *
12517 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
12518 * configuration. Each pin widget can choose any input DACs and a mixer.
12519 * Each ADC is connected from a mixer of all inputs. This makes possible
12520 * 6-channel independent captures.
12521 *
12522 * In addition, an independent DAC for the multi-playback (not used in this
12523 * driver yet).
12524 */
12525#define ALC662_DIGOUT_NID 0x06
12526#define ALC662_DIGIN_NID 0x0a
12527
12528static hda_nid_t alc662_dac_nids[4] = {
12529 /* front, rear, clfe, rear_surr */
12530 0x02, 0x03, 0x04
12531};
12532
12533static hda_nid_t alc662_adc_nids[1] = {
12534 /* ADC1-2 */
12535 0x09,
12536};
12537/* input MUX */
12538/* FIXME: should be a matrix-type input source selection */
12539
12540static struct hda_input_mux alc662_capture_source = {
12541 .num_items = 4,
12542 .items = {
12543 { "Mic", 0x0 },
12544 { "Front Mic", 0x1 },
12545 { "Line", 0x2 },
12546 { "CD", 0x4 },
12547 },
12548};
12549
12550static struct hda_input_mux alc662_lenovo_101e_capture_source = {
12551 .num_items = 2,
12552 .items = {
12553 { "Mic", 0x1 },
12554 { "Line", 0x2 },
12555 },
12556};
Kailang Yang291702f2007-10-16 14:28:03 +020012557
12558static struct hda_input_mux alc662_eeepc_capture_source = {
12559 .num_items = 2,
12560 .items = {
12561 { "i-Mic", 0x1 },
12562 { "e-Mic", 0x0 },
12563 },
12564};
12565
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012566#define alc662_mux_enum_info alc_mux_enum_info
12567#define alc662_mux_enum_get alc_mux_enum_get
12568
12569static int alc662_mux_enum_put(struct snd_kcontrol *kcontrol,
12570 struct snd_ctl_elem_value *ucontrol)
12571{
12572 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
12573 struct alc_spec *spec = codec->spec;
12574 const struct hda_input_mux *imux = spec->input_mux;
12575 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Kailang Yangd1a991a2007-08-15 16:21:59 +020012576 static hda_nid_t capture_mixers[2] = { 0x23, 0x22 };
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012577 hda_nid_t nid = capture_mixers[adc_idx];
12578 unsigned int *cur_val = &spec->cur_mux[adc_idx];
12579 unsigned int i, idx;
12580
12581 idx = ucontrol->value.enumerated.item[0];
12582 if (idx >= imux->num_items)
12583 idx = imux->num_items - 1;
Takashi Iwai82beb8f2007-08-10 17:09:26 +020012584 if (*cur_val == idx)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012585 return 0;
12586 for (i = 0; i < imux->num_items; i++) {
Takashi Iwai47fd8302007-08-10 17:11:07 +020012587 unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
12588 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
12589 imux->items[i].index,
12590 HDA_AMP_MUTE, v);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012591 }
12592 *cur_val = idx;
12593 return 1;
12594}
12595/*
12596 * 2ch mode
12597 */
12598static struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
12599 { 2, NULL }
12600};
12601
12602/*
12603 * 2ch mode
12604 */
12605static struct hda_verb alc662_3ST_ch2_init[] = {
12606 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
12607 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
12608 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
12609 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
12610 { } /* end */
12611};
12612
12613/*
12614 * 6ch mode
12615 */
12616static struct hda_verb alc662_3ST_ch6_init[] = {
12617 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12618 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12619 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
12620 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12621 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12622 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
12623 { } /* end */
12624};
12625
12626static struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
12627 { 2, alc662_3ST_ch2_init },
12628 { 6, alc662_3ST_ch6_init },
12629};
12630
12631/*
12632 * 2ch mode
12633 */
12634static struct hda_verb alc662_sixstack_ch6_init[] = {
12635 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12636 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12637 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12638 { } /* end */
12639};
12640
12641/*
12642 * 6ch mode
12643 */
12644static struct hda_verb alc662_sixstack_ch8_init[] = {
12645 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12646 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12647 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12648 { } /* end */
12649};
12650
12651static struct hda_channel_mode alc662_5stack_modes[2] = {
12652 { 2, alc662_sixstack_ch6_init },
12653 { 6, alc662_sixstack_ch8_init },
12654};
12655
12656/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
12657 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
12658 */
12659
12660static struct snd_kcontrol_new alc662_base_mixer[] = {
12661 /* output mixer control */
12662 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12663 HDA_CODEC_MUTE("Front Playback Switch", 0x02, 0x0, HDA_OUTPUT),
12664 HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12665 HDA_CODEC_MUTE("Surround Playback Switch", 0x03, 0x0, HDA_OUTPUT),
12666 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
12667 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
12668 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT),
12669 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT),
12670 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
12671
12672 /*Input mixer control */
12673 HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
12674 HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
12675 HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
12676 HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
12677 HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
12678 HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
12679 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
12680 HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012681 { } /* end */
12682};
12683
12684static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
12685 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12686 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
12687 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
12688 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
12689 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
12690 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
12691 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
12692 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12693 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12694 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12695 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
12696 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
12697 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012698 { } /* end */
12699};
12700
12701static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
12702 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12703 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
12704 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
12705 HDA_BIND_MUTE("Surround Playback Switch", 0x03, 2, HDA_INPUT),
12706 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
12707 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
12708 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT),
12709 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT),
12710 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
12711 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
12712 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
12713 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
12714 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
12715 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12716 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12717 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12718 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
12719 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
12720 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012721 { } /* end */
12722};
12723
12724static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
12725 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12726 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
12727 HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
12728 HDA_BIND_MUTE("iSpeaker Playback Switch", 0x03, 2, HDA_INPUT),
12729 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
12730 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
12731 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
12732 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12733 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012734 { } /* end */
12735};
12736
Kailang Yang291702f2007-10-16 14:28:03 +020012737static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
12738 HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12739
12740 HDA_CODEC_VOLUME("LineOut Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12741 HDA_CODEC_MUTE("LineOut Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
12742
12743 HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT),
12744 HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12745 HDA_CODEC_MUTE("e-Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12746
12747 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
12748 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12749 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
12750 { } /* end */
12751};
12752
Kailang Yang8c427222008-01-10 13:03:59 +010012753static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
12754 HDA_CODEC_VOLUME("LineOut Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12755 HDA_CODEC_MUTE("LineOut Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12756 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
12757 HDA_BIND_MUTE("Surround Playback Switch", 0x03, 2, HDA_INPUT),
12758 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
12759 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
12760 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT),
12761 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT),
12762 HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
12763 HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
12764 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
12765 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
12766 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12767 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12768 { } /* end */
12769};
12770
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012771static struct snd_kcontrol_new alc662_chmode_mixer[] = {
12772 {
12773 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12774 .name = "Channel Mode",
12775 .info = alc_ch_mode_info,
12776 .get = alc_ch_mode_get,
12777 .put = alc_ch_mode_put,
12778 },
12779 { } /* end */
12780};
12781
12782static struct hda_verb alc662_init_verbs[] = {
12783 /* ADC: mute amp left and right */
12784 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12785 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12786 /* Front mixer: unmute input/output amp left and right (volume = 0) */
12787
Takashi Iwaicb53c622007-08-10 17:21:45 +020012788 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12789 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12790 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12791 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12792 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012793
Kailang Yangb60dd392007-09-20 12:50:29 +020012794 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12795 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12796 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12797 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12798 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12799 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012800
12801 /* Front Pin: output 0 (0x0c) */
12802 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12803 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12804
12805 /* Rear Pin: output 1 (0x0d) */
12806 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12807 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12808
12809 /* CLFE Pin: output 2 (0x0e) */
12810 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12811 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12812
12813 /* Mic (rear) pin: input vref at 80% */
12814 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12815 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12816 /* Front Mic pin: input vref at 80% */
12817 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12818 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12819 /* Line In pin: input */
12820 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12821 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12822 /* Line-2 In: Headphone output (output 0 - 0x0c) */
12823 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12824 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12825 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
12826 /* CD pin widget for input */
12827 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12828
12829 /* FIXME: use matrix-type input source selection */
12830 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
12831 /* Input mixer */
12832 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12833 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12834 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12835 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Kailang Yang291702f2007-10-16 14:28:03 +020012836
12837 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12838 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12839 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12840 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012841 { }
12842};
12843
12844static struct hda_verb alc662_sue_init_verbs[] = {
12845 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
12846 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
Kailang Yang291702f2007-10-16 14:28:03 +020012847 {}
12848};
12849
12850static struct hda_verb alc662_eeepc_sue_init_verbs[] = {
12851 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
12852 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12853 {}
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012854};
12855
Kailang Yang8c427222008-01-10 13:03:59 +010012856/* Set Unsolicited Event*/
12857static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
12858 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12859 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12860 {}
12861};
12862
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012863/*
12864 * generic initialization of ADC, input mixers and output mixers
12865 */
12866static struct hda_verb alc662_auto_init_verbs[] = {
12867 /*
12868 * Unmute ADC and set the default input to mic-in
12869 */
12870 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12871 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12872
12873 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
12874 * mixer widget
12875 * Note: PASD motherboards uses the Line In 2 as the input for front
12876 * panel mic (mic 2)
12877 */
12878 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020012879 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12880 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12881 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12882 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12883 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012884
12885 /*
12886 * Set up output mixers (0x0c - 0x0f)
12887 */
12888 /* set vol=0 to output mixers */
12889 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12890 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12891 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12892
12893 /* set up input amps for analog loopback */
12894 /* Amp Indices: DAC = 0, mixer = 1 */
Kailang Yangb60dd392007-09-20 12:50:29 +020012895 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12896 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12897 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12898 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12899 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12900 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012901
12902
12903 /* FIXME: use matrix-type input source selection */
12904 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
12905 /* Input mixer */
12906 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangd1a991a2007-08-15 16:21:59 +020012907 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012908 { }
12909};
12910
12911/* capture mixer elements */
12912static struct snd_kcontrol_new alc662_capture_mixer[] = {
12913 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
12914 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
12915 {
12916 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12917 /* The multiple "Capture Source" controls confuse alsamixer
12918 * So call somewhat different..
12919 * FIXME: the controls appear in the "playback" view!
12920 */
12921 /* .name = "Capture Source", */
12922 .name = "Input Source",
12923 .count = 1,
Herton Ronaldo Krzesinski6e7939b2007-12-19 17:49:02 +010012924 .info = alc662_mux_enum_info,
12925 .get = alc662_mux_enum_get,
12926 .put = alc662_mux_enum_put,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012927 },
12928 { } /* end */
12929};
12930
12931static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
12932{
12933 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012934 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012935
12936 present = snd_hda_codec_read(codec, 0x14, 0,
12937 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020012938 bits = present ? HDA_AMP_MUTE : 0;
12939 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
12940 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012941}
12942
12943static void alc662_lenovo_101e_all_automute(struct hda_codec *codec)
12944{
12945 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012946 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012947
12948 present = snd_hda_codec_read(codec, 0x1b, 0,
12949 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020012950 bits = present ? HDA_AMP_MUTE : 0;
12951 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
12952 HDA_AMP_MUTE, bits);
12953 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
12954 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012955}
12956
12957static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec,
12958 unsigned int res)
12959{
12960 if ((res >> 26) == ALC880_HP_EVENT)
12961 alc662_lenovo_101e_all_automute(codec);
12962 if ((res >> 26) == ALC880_FRONT_EVENT)
12963 alc662_lenovo_101e_ispeaker_automute(codec);
12964}
12965
Kailang Yang291702f2007-10-16 14:28:03 +020012966static void alc662_eeepc_mic_automute(struct hda_codec *codec)
12967{
12968 unsigned int present;
12969
12970 present = snd_hda_codec_read(codec, 0x18, 0,
12971 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12972 snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
12973 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
12974 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
12975 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
12976 snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
12977 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
12978 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
12979 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
12980}
12981
12982/* unsolicited event for HP jack sensing */
12983static void alc662_eeepc_unsol_event(struct hda_codec *codec,
12984 unsigned int res)
12985{
12986 if ((res >> 26) == ALC880_HP_EVENT)
12987 alc262_hippo1_automute( codec );
12988
12989 if ((res >> 26) == ALC880_MIC_EVENT)
12990 alc662_eeepc_mic_automute(codec);
12991}
12992
12993static void alc662_eeepc_inithook(struct hda_codec *codec)
12994{
12995 alc262_hippo1_automute( codec );
12996 alc662_eeepc_mic_automute(codec);
12997}
12998
Kailang Yang8c427222008-01-10 13:03:59 +010012999static void alc662_eeepc_ep20_automute(struct hda_codec *codec)
13000{
13001 unsigned int mute;
13002 unsigned int present;
13003
13004 snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
13005 present = snd_hda_codec_read(codec, 0x14, 0,
13006 AC_VERB_GET_PIN_SENSE, 0);
13007 present = (present & 0x80000000) != 0;
13008 if (present) {
13009 /* mute internal speaker */
13010 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
13011 HDA_AMP_MUTE, HDA_AMP_MUTE);
13012 } else {
13013 /* unmute internal speaker if necessary */
13014 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
13015 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
13016 HDA_AMP_MUTE, mute);
13017 }
13018}
13019
13020/* unsolicited event for HP jack sensing */
13021static void alc662_eeepc_ep20_unsol_event(struct hda_codec *codec,
13022 unsigned int res)
13023{
13024 if ((res >> 26) == ALC880_HP_EVENT)
13025 alc662_eeepc_ep20_automute(codec);
13026}
13027
13028static void alc662_eeepc_ep20_inithook(struct hda_codec *codec)
13029{
13030 alc662_eeepc_ep20_automute(codec);
13031}
13032
Takashi Iwaicb53c622007-08-10 17:21:45 +020013033#ifdef CONFIG_SND_HDA_POWER_SAVE
13034#define alc662_loopbacks alc880_loopbacks
13035#endif
13036
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013037
13038/* pcm configuration: identiacal with ALC880 */
13039#define alc662_pcm_analog_playback alc880_pcm_analog_playback
13040#define alc662_pcm_analog_capture alc880_pcm_analog_capture
13041#define alc662_pcm_digital_playback alc880_pcm_digital_playback
13042#define alc662_pcm_digital_capture alc880_pcm_digital_capture
13043
13044/*
13045 * configuration and preset
13046 */
13047static const char *alc662_models[ALC662_MODEL_LAST] = {
13048 [ALC662_3ST_2ch_DIG] = "3stack-dig",
13049 [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
13050 [ALC662_3ST_6ch] = "3stack-6ch",
13051 [ALC662_5ST_DIG] = "6stack-dig",
13052 [ALC662_LENOVO_101E] = "lenovo-101e",
Takashi Iwaib995d762007-10-17 10:41:06 +020013053 [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
Kailang Yang8c427222008-01-10 13:03:59 +010013054 [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013055 [ALC662_AUTO] = "auto",
13056};
13057
13058static struct snd_pci_quirk alc662_cfg_tbl[] = {
Kailang Yang291702f2007-10-16 14:28:03 +020013059 SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
Kailang Yang8c427222008-01-10 13:03:59 +010013060 SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013061 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013062 {}
13063};
13064
13065static struct alc_config_preset alc662_presets[] = {
13066 [ALC662_3ST_2ch_DIG] = {
Kailang Yang291702f2007-10-16 14:28:03 +020013067 .mixers = { alc662_3ST_2ch_mixer, alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013068 .init_verbs = { alc662_init_verbs },
13069 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13070 .dac_nids = alc662_dac_nids,
13071 .dig_out_nid = ALC662_DIGOUT_NID,
13072 .num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
13073 .adc_nids = alc662_adc_nids,
13074 .dig_in_nid = ALC662_DIGIN_NID,
13075 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
13076 .channel_mode = alc662_3ST_2ch_modes,
13077 .input_mux = &alc662_capture_source,
13078 },
13079 [ALC662_3ST_6ch_DIG] = {
Kailang Yang291702f2007-10-16 14:28:03 +020013080 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer,
13081 alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013082 .init_verbs = { alc662_init_verbs },
13083 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13084 .dac_nids = alc662_dac_nids,
13085 .dig_out_nid = ALC662_DIGOUT_NID,
13086 .num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
13087 .adc_nids = alc662_adc_nids,
13088 .dig_in_nid = ALC662_DIGIN_NID,
13089 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
13090 .channel_mode = alc662_3ST_6ch_modes,
13091 .need_dac_fix = 1,
13092 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013093 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013094 [ALC662_3ST_6ch] = {
Kailang Yang291702f2007-10-16 14:28:03 +020013095 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer,
13096 alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013097 .init_verbs = { alc662_init_verbs },
13098 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13099 .dac_nids = alc662_dac_nids,
13100 .num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
13101 .adc_nids = alc662_adc_nids,
13102 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
13103 .channel_mode = alc662_3ST_6ch_modes,
13104 .need_dac_fix = 1,
13105 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013106 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013107 [ALC662_5ST_DIG] = {
Kailang Yang291702f2007-10-16 14:28:03 +020013108 .mixers = { alc662_base_mixer, alc662_chmode_mixer,
13109 alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013110 .init_verbs = { alc662_init_verbs },
13111 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13112 .dac_nids = alc662_dac_nids,
13113 .dig_out_nid = ALC662_DIGOUT_NID,
13114 .num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
13115 .adc_nids = alc662_adc_nids,
13116 .dig_in_nid = ALC662_DIGIN_NID,
13117 .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
13118 .channel_mode = alc662_5stack_modes,
13119 .input_mux = &alc662_capture_source,
13120 },
13121 [ALC662_LENOVO_101E] = {
Kailang Yang291702f2007-10-16 14:28:03 +020013122 .mixers = { alc662_lenovo_101e_mixer, alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013123 .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
13124 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13125 .dac_nids = alc662_dac_nids,
13126 .num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
13127 .adc_nids = alc662_adc_nids,
13128 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
13129 .channel_mode = alc662_3ST_2ch_modes,
13130 .input_mux = &alc662_lenovo_101e_capture_source,
13131 .unsol_event = alc662_lenovo_101e_unsol_event,
13132 .init_hook = alc662_lenovo_101e_all_automute,
13133 },
Kailang Yang291702f2007-10-16 14:28:03 +020013134 [ALC662_ASUS_EEEPC_P701] = {
13135 .mixers = { alc662_eeepc_p701_mixer, alc662_capture_mixer },
13136 .init_verbs = { alc662_init_verbs,
13137 alc662_eeepc_sue_init_verbs },
13138 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13139 .dac_nids = alc662_dac_nids,
13140 .num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids),
13141 .adc_nids = alc662_adc_nids,
13142 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
13143 .channel_mode = alc662_3ST_2ch_modes,
13144 .input_mux = &alc662_eeepc_capture_source,
13145 .unsol_event = alc662_eeepc_unsol_event,
13146 .init_hook = alc662_eeepc_inithook,
13147 },
Kailang Yang8c427222008-01-10 13:03:59 +010013148 [ALC662_ASUS_EEEPC_EP20] = {
13149 .mixers = { alc662_eeepc_ep20_mixer, alc662_capture_mixer,
13150 alc662_chmode_mixer },
13151 .init_verbs = { alc662_init_verbs,
13152 alc662_eeepc_ep20_sue_init_verbs },
13153 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13154 .dac_nids = alc662_dac_nids,
13155 .num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
13156 .adc_nids = alc662_adc_nids,
13157 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
13158 .channel_mode = alc662_3ST_6ch_modes,
13159 .input_mux = &alc662_lenovo_101e_capture_source,
13160 .unsol_event = alc662_eeepc_ep20_unsol_event,
13161 .init_hook = alc662_eeepc_ep20_inithook,
13162 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013163
13164};
13165
13166
13167/*
13168 * BIOS auto configuration
13169 */
13170
13171/* add playback controls from the parsed DAC table */
13172static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec,
13173 const struct auto_pin_cfg *cfg)
13174{
13175 char name[32];
13176 static const char *chname[4] = {
13177 "Front", "Surround", NULL /*CLFE*/, "Side"
13178 };
13179 hda_nid_t nid;
13180 int i, err;
13181
13182 for (i = 0; i < cfg->line_outs; i++) {
13183 if (!spec->multiout.dac_nids[i])
13184 continue;
Kailang Yangb60dd392007-09-20 12:50:29 +020013185 nid = alc880_idx_to_dac(i);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013186 if (i == 2) {
13187 /* Center/LFE */
13188 err = add_control(spec, ALC_CTL_WIDGET_VOL,
13189 "Center Playback Volume",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013190 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
13191 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013192 if (err < 0)
13193 return err;
13194 err = add_control(spec, ALC_CTL_WIDGET_VOL,
13195 "LFE Playback Volume",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013196 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
13197 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013198 if (err < 0)
13199 return err;
13200 err = add_control(spec, ALC_CTL_BIND_MUTE,
13201 "Center Playback Switch",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013202 HDA_COMPOSE_AMP_VAL(nid, 1, 2,
13203 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013204 if (err < 0)
13205 return err;
13206 err = add_control(spec, ALC_CTL_BIND_MUTE,
13207 "LFE Playback Switch",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013208 HDA_COMPOSE_AMP_VAL(nid, 2, 2,
13209 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013210 if (err < 0)
13211 return err;
13212 } else {
13213 sprintf(name, "%s Playback Volume", chname[i]);
13214 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013215 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
13216 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013217 if (err < 0)
13218 return err;
13219 sprintf(name, "%s Playback Switch", chname[i]);
13220 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013221 HDA_COMPOSE_AMP_VAL(nid, 3, 2,
13222 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013223 if (err < 0)
13224 return err;
13225 }
13226 }
13227 return 0;
13228}
13229
13230/* add playback controls for speaker and HP outputs */
13231static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
13232 const char *pfx)
13233{
13234 hda_nid_t nid;
13235 int err;
13236 char name[32];
13237
13238 if (!pin)
13239 return 0;
13240
13241 if (alc880_is_fixed_pin(pin)) {
13242 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
13243 /* printk("DAC nid=%x\n",nid); */
13244 /* specify the DAC as the extra output */
13245 if (!spec->multiout.hp_nid)
13246 spec->multiout.hp_nid = nid;
13247 else
13248 spec->multiout.extra_out_nid[0] = nid;
13249 /* control HP volume/switch on the output mixer amp */
13250 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
13251 sprintf(name, "%s Playback Volume", pfx);
13252 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
13253 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
13254 if (err < 0)
13255 return err;
13256 sprintf(name, "%s Playback Switch", pfx);
13257 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
13258 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
13259 if (err < 0)
13260 return err;
13261 } else if (alc880_is_multi_pin(pin)) {
13262 /* set manual connection */
13263 /* we have only a switch on HP-out PIN */
13264 sprintf(name, "%s Playback Switch", pfx);
13265 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
13266 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
13267 if (err < 0)
13268 return err;
13269 }
13270 return 0;
13271}
13272
13273/* create playback/capture controls for input pins */
13274static int alc662_auto_create_analog_input_ctls(struct alc_spec *spec,
13275 const struct auto_pin_cfg *cfg)
13276{
13277 struct hda_input_mux *imux = &spec->private_imux;
13278 int i, err, idx;
13279
13280 for (i = 0; i < AUTO_PIN_LAST; i++) {
13281 if (alc880_is_input_pin(cfg->input_pins[i])) {
13282 idx = alc880_input_pin_idx(cfg->input_pins[i]);
13283 err = new_analog_input(spec, cfg->input_pins[i],
13284 auto_pin_cfg_labels[i],
13285 idx, 0x0b);
13286 if (err < 0)
13287 return err;
13288 imux->items[imux->num_items].label =
13289 auto_pin_cfg_labels[i];
13290 imux->items[imux->num_items].index =
13291 alc880_input_pin_idx(cfg->input_pins[i]);
13292 imux->num_items++;
13293 }
13294 }
13295 return 0;
13296}
13297
13298static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
13299 hda_nid_t nid, int pin_type,
13300 int dac_idx)
13301{
13302 /* set as output */
13303 snd_hda_codec_write(codec, nid, 0,
13304 AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
13305 snd_hda_codec_write(codec, nid, 0,
13306 AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
13307 /* need the manual connection? */
13308 if (alc880_is_multi_pin(nid)) {
13309 struct alc_spec *spec = codec->spec;
13310 int idx = alc880_multi_pin_idx(nid);
13311 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
13312 AC_VERB_SET_CONNECT_SEL,
13313 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
13314 }
13315}
13316
13317static void alc662_auto_init_multi_out(struct hda_codec *codec)
13318{
13319 struct alc_spec *spec = codec->spec;
13320 int i;
13321
Kailang Yang8c427222008-01-10 13:03:59 +010013322 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013323 for (i = 0; i <= HDA_SIDE; i++) {
13324 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020013325 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013326 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020013327 alc662_auto_set_output_and_unmute(codec, nid, pin_type,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013328 i);
13329 }
13330}
13331
13332static void alc662_auto_init_hp_out(struct hda_codec *codec)
13333{
13334 struct alc_spec *spec = codec->spec;
13335 hda_nid_t pin;
13336
13337 pin = spec->autocfg.hp_pins[0];
13338 if (pin) /* connect to front */
13339 /* use dac 0 */
13340 alc662_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
13341}
13342
13343#define alc662_is_input_pin(nid) alc880_is_input_pin(nid)
13344#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID
13345
13346static void alc662_auto_init_analog_input(struct hda_codec *codec)
13347{
13348 struct alc_spec *spec = codec->spec;
13349 int i;
13350
13351 for (i = 0; i < AUTO_PIN_LAST; i++) {
13352 hda_nid_t nid = spec->autocfg.input_pins[i];
13353 if (alc662_is_input_pin(nid)) {
13354 snd_hda_codec_write(codec, nid, 0,
13355 AC_VERB_SET_PIN_WIDGET_CONTROL,
13356 (i <= AUTO_PIN_FRONT_MIC ?
13357 PIN_VREF80 : PIN_IN));
13358 if (nid != ALC662_PIN_CD_NID)
13359 snd_hda_codec_write(codec, nid, 0,
13360 AC_VERB_SET_AMP_GAIN_MUTE,
13361 AMP_OUT_MUTE);
13362 }
13363 }
13364}
13365
13366static int alc662_parse_auto_config(struct hda_codec *codec)
13367{
13368 struct alc_spec *spec = codec->spec;
13369 int err;
13370 static hda_nid_t alc662_ignore[] = { 0x1d, 0 };
13371
13372 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
13373 alc662_ignore);
13374 if (err < 0)
13375 return err;
13376 if (!spec->autocfg.line_outs)
13377 return 0; /* can't find valid BIOS pin config */
13378
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013379 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
13380 if (err < 0)
13381 return err;
13382 err = alc662_auto_create_multi_out_ctls(spec, &spec->autocfg);
13383 if (err < 0)
13384 return err;
13385 err = alc662_auto_create_extra_out(spec,
13386 spec->autocfg.speaker_pins[0],
13387 "Speaker");
13388 if (err < 0)
13389 return err;
13390 err = alc662_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
13391 "Headphone");
13392 if (err < 0)
13393 return err;
13394 err = alc662_auto_create_analog_input_ctls(spec, &spec->autocfg);
13395 if (err < 0)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013396 return err;
13397
13398 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
13399
13400 if (spec->autocfg.dig_out_pin)
13401 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
13402
13403 if (spec->kctl_alloc)
13404 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
13405
13406 spec->num_mux_defs = 1;
13407 spec->input_mux = &spec->private_imux;
13408
Takashi Iwai8c87286f2007-06-19 12:11:16 +020013409 spec->init_verbs[spec->num_init_verbs++] = alc662_auto_init_verbs;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013410 spec->mixers[spec->num_mixers] = alc662_capture_mixer;
13411 spec->num_mixers++;
Takashi Iwai8c87286f2007-06-19 12:11:16 +020013412 return 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013413}
13414
13415/* additional initialization for auto-configuration model */
13416static void alc662_auto_init(struct hda_codec *codec)
13417{
13418 alc662_auto_init_multi_out(codec);
13419 alc662_auto_init_hp_out(codec);
13420 alc662_auto_init_analog_input(codec);
13421}
13422
13423static int patch_alc662(struct hda_codec *codec)
13424{
13425 struct alc_spec *spec;
13426 int err, board_config;
13427
13428 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
13429 if (!spec)
13430 return -ENOMEM;
13431
13432 codec->spec = spec;
13433
13434 board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
13435 alc662_models,
13436 alc662_cfg_tbl);
13437 if (board_config < 0) {
13438 printk(KERN_INFO "hda_codec: Unknown model for ALC662, "
13439 "trying auto-probe from BIOS...\n");
13440 board_config = ALC662_AUTO;
13441 }
13442
13443 if (board_config == ALC662_AUTO) {
13444 /* automatic parse from the BIOS config */
13445 err = alc662_parse_auto_config(codec);
13446 if (err < 0) {
13447 alc_free(codec);
13448 return err;
Takashi Iwai8c87286f2007-06-19 12:11:16 +020013449 } else if (!err) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013450 printk(KERN_INFO
13451 "hda_codec: Cannot set up configuration "
13452 "from BIOS. Using base mode...\n");
13453 board_config = ALC662_3ST_2ch_DIG;
13454 }
13455 }
13456
13457 if (board_config != ALC662_AUTO)
13458 setup_preset(spec, &alc662_presets[board_config]);
13459
13460 spec->stream_name_analog = "ALC662 Analog";
13461 spec->stream_analog_playback = &alc662_pcm_analog_playback;
13462 spec->stream_analog_capture = &alc662_pcm_analog_capture;
13463
13464 spec->stream_name_digital = "ALC662 Digital";
13465 spec->stream_digital_playback = &alc662_pcm_digital_playback;
13466 spec->stream_digital_capture = &alc662_pcm_digital_capture;
13467
13468 if (!spec->adc_nids && spec->input_mux) {
13469 spec->adc_nids = alc662_adc_nids;
13470 spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
13471 }
13472
Takashi Iwai2134ea42008-01-10 16:53:55 +010013473 spec->vmaster_nid = 0x02;
13474
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013475 codec->patch_ops = alc_patch_ops;
13476 if (board_config == ALC662_AUTO)
13477 spec->init_hook = alc662_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020013478#ifdef CONFIG_SND_HDA_POWER_SAVE
13479 if (!spec->loopback.amplist)
13480 spec->loopback.amplist = alc662_loopbacks;
13481#endif
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013482
13483 return 0;
13484}
13485
13486/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070013487 * patch entries
13488 */
13489struct hda_codec_preset snd_hda_preset_realtek[] = {
13490 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +010013491 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +010013492 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +020013493 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +010013494 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013495 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013496 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013497 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
13498 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
13499 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013500 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
13501 .patch = patch_alc883 },
13502 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
13503 .patch = patch_alc662 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013504 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070013505 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013506 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 },
Kailang Yangdf694da2005-12-05 19:42:22 +010013507 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013508 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 },
Kailang Yangf6a92242007-12-13 16:52:54 +010013509 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc883 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070013510 {} /* terminator */
13511};