blob: 355d88d07ea26fa49545cd3a2c2ff2e007a9756c [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Universal Interface for Intel High Definition Audio Codec
3 *
4 * HD audio interface patch for ALC 260/880/882 codecs
5 *
Kailang Yangdf694da2005-12-05 19:42:22 +01006 * Copyright (c) 2004 Kailang Yang <kailang@realtek.com.tw>
7 * PeiSen Hou <pshou@realtek.com.tw>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * Takashi Iwai <tiwai@suse.de>
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01009 * Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
11 * This driver is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This driver is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
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 Woithe7cf51e42006-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,
Takashi Iwai3866f0b2008-01-15 12:37:42 +0100109 ALC268_DELL,
Mirco Tischlerf12462c2008-02-04 12:33:59 +0100110 ALC268_ZEPTO,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +0100111#ifdef CONFIG_SND_DEBUG
112 ALC268_TEST,
113#endif
Kailang Yanga361d842007-06-05 12:30:55 +0200114 ALC268_AUTO,
115 ALC268_MODEL_LAST /* last tag */
116};
117
Kailang Yangf6a92242007-12-13 16:52:54 +0100118/* ALC269 models */
119enum {
120 ALC269_BASIC,
121 ALC269_AUTO,
122 ALC269_MODEL_LAST /* last tag */
123};
124
Kailang Yangdf694da2005-12-05 19:42:22 +0100125/* ALC861 models */
126enum {
127 ALC861_3ST,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200128 ALC660_3ST,
Kailang Yangdf694da2005-12-05 19:42:22 +0100129 ALC861_3ST_DIG,
130 ALC861_6ST_DIG,
Takashi Iwai22309c32006-08-09 16:57:28 +0200131 ALC861_UNIWILL_M31,
Tobin Davisa53d1ae2006-10-17 12:00:28 +0200132 ALC861_TOSHIBA,
Mariusz Domanski7cdbff92006-10-23 13:42:56 +0200133 ALC861_ASUS,
Takashi Iwai56bb0ca2006-11-22 11:52:52 +0100134 ALC861_ASUS_LAPTOP,
Kailang Yangdf694da2005-12-05 19:42:22 +0100135 ALC861_AUTO,
136 ALC861_MODEL_LAST,
137};
138
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100139/* ALC861-VD models */
140enum {
141 ALC660VD_3ST,
Mike Crash6963f842007-06-25 12:12:51 +0200142 ALC660VD_3ST_DIG,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100143 ALC861VD_3ST,
144 ALC861VD_3ST_DIG,
145 ALC861VD_6ST_DIG,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200146 ALC861VD_LENOVO,
Kailang Yang272a5272007-05-14 11:00:38 +0200147 ALC861VD_DALLAS,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200148 ALC861VD_HP,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100149 ALC861VD_AUTO,
150 ALC861VD_MODEL_LAST,
151};
152
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200153/* ALC662 models */
154enum {
155 ALC662_3ST_2ch_DIG,
156 ALC662_3ST_6ch_DIG,
157 ALC662_3ST_6ch,
158 ALC662_5ST_DIG,
159 ALC662_LENOVO_101E,
Kailang Yang291702f2007-10-16 14:28:03 +0200160 ALC662_ASUS_EEEPC_P701,
Kailang Yang8c427222008-01-10 13:03:59 +0100161 ALC662_ASUS_EEEPC_EP20,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200162 ALC662_AUTO,
163 ALC662_MODEL_LAST,
164};
165
Kailang Yangdf694da2005-12-05 19:42:22 +0100166/* ALC882 models */
167enum {
168 ALC882_3ST_DIG,
169 ALC882_6ST_DIG,
Takashi Iwai4b146cb2006-07-28 14:42:36 +0200170 ALC882_ARIMA,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200171 ALC882_W2JC,
Kailang Yang272a5272007-05-14 11:00:38 +0200172 ALC882_TARGA,
173 ALC882_ASUS_A7J,
Takashi Iwai914759b2007-09-06 14:52:04 +0200174 ALC882_ASUS_A7M,
Tobin Davis9102cd12006-12-15 10:02:12 +0100175 ALC885_MACPRO,
Takashi Iwai87350ad2007-08-16 18:19:38 +0200176 ALC885_MBP3,
Nicola Fagnanic54728d2007-07-19 23:28:52 +0200177 ALC885_IMAC24,
Kailang Yang272a5272007-05-14 11:00:38 +0200178 ALC882_AUTO,
Kailang Yangdf694da2005-12-05 19:42:22 +0100179 ALC882_MODEL_LAST,
180};
181
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200182/* ALC883 models */
183enum {
184 ALC883_3ST_2ch_DIG,
185 ALC883_3ST_6ch_DIG,
186 ALC883_3ST_6ch,
187 ALC883_6ST_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +0200188 ALC883_TARGA_DIG,
189 ALC883_TARGA_2ch_DIG,
Vladimir Avdoninbab282b2006-08-22 13:31:58 +0200190 ALC883_ACER,
Tobin Davis2880a862007-08-07 11:50:26 +0200191 ALC883_ACER_ASPIRE,
Tobin Davisc07584c2006-10-13 12:32:16 +0200192 ALC883_MEDION,
Kailang Yang272a5272007-05-14 11:00:38 +0200193 ALC883_MEDION_MD2,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +0100194 ALC883_LAPTOP_EAPD,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200195 ALC883_LENOVO_101E_2ch,
Kailang Yang272a5272007-05-14 11:00:38 +0200196 ALC883_LENOVO_NB0763,
Kailang Yang189609a2007-08-20 11:31:23 +0200197 ALC888_LENOVO_MS7195_DIG,
198 ALC883_HAIER_W66,
Claudio Matsuoka4723c022007-07-13 14:36:19 +0200199 ALC888_6ST_HP,
200 ALC888_3ST_HP,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +0100201 ALC888_6ST_DELL,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +0100202 ALC883_MITAC,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200203 ALC883_AUTO,
204 ALC883_MODEL_LAST,
205};
206
Kailang Yangdf694da2005-12-05 19:42:22 +0100207/* for GPIO Poll */
208#define GPIO_MASK 0x03
209
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210struct alc_spec {
211 /* codec parameterization */
Kailang Yangdf694da2005-12-05 19:42:22 +0100212 struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 unsigned int num_mixers;
214
Kailang Yangdf694da2005-12-05 19:42:22 +0100215 const struct hda_verb *init_verbs[5]; /* initialization verbs
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200216 * don't forget NULL
217 * termination!
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200218 */
219 unsigned int num_init_verbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220
Takashi Iwai16ded522005-06-10 19:58:24 +0200221 char *stream_name_analog; /* analog PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 struct hda_pcm_stream *stream_analog_playback;
223 struct hda_pcm_stream *stream_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +0100224 struct hda_pcm_stream *stream_analog_alt_playback;
225 struct hda_pcm_stream *stream_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200227 char *stream_name_digital; /* digital PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 struct hda_pcm_stream *stream_digital_playback;
229 struct hda_pcm_stream *stream_digital_capture;
230
231 /* playback */
Takashi Iwai16ded522005-06-10 19:58:24 +0200232 struct hda_multi_out multiout; /* playback set-up
233 * max_channels, dacs must be set
234 * dig_out_nid and hp_nid are optional
235 */
Takashi Iwai63300792008-01-24 15:31:36 +0100236 hda_nid_t alt_dac_nid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237
238 /* capture */
239 unsigned int num_adc_nids;
240 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100241 hda_nid_t *capsrc_nids;
Takashi Iwai16ded522005-06-10 19:58:24 +0200242 hda_nid_t dig_in_nid; /* digital-in NID; optional */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243
244 /* capture source */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200245 unsigned int num_mux_defs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 const struct hda_input_mux *input_mux;
247 unsigned int cur_mux[3];
248
249 /* channel model */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100250 const struct hda_channel_mode *channel_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 int num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200252 int need_dac_fix;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253
254 /* PCM information */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100255 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
Takashi Iwai41e41f12005-06-08 14:48:49 +0200256
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200257 /* dynamic controls, init_verbs and input_mux */
258 struct auto_pin_cfg autocfg;
259 unsigned int num_kctl_alloc, num_kctl_used;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100260 struct snd_kcontrol_new *kctl_alloc;
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200261 struct hda_input_mux private_imux;
Takashi Iwai41923e42007-10-22 17:20:10 +0200262 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai834be882006-03-01 14:16:17 +0100263
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100264 /* hooks */
265 void (*init_hook)(struct hda_codec *codec);
266 void (*unsol_event)(struct hda_codec *codec, unsigned int res);
267
Takashi Iwai834be882006-03-01 14:16:17 +0100268 /* for pin sensing */
269 unsigned int sense_updated: 1;
270 unsigned int jack_present: 1;
Takashi Iwaibec15c32008-01-28 18:16:30 +0100271 unsigned int master_sw: 1;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200272
Takashi Iwai2134ea42008-01-10 16:53:55 +0100273 /* for virtual master */
274 hda_nid_t vmaster_nid;
275 u32 vmaster_tlv[4];
Takashi Iwaicb53c622007-08-10 17:21:45 +0200276#ifdef CONFIG_SND_HDA_POWER_SAVE
277 struct hda_loopback_check loopback;
278#endif
Kailang Yangdf694da2005-12-05 19:42:22 +0100279};
280
281/*
282 * configuration template - to be copied to the spec instance
283 */
284struct alc_config_preset {
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200285 struct snd_kcontrol_new *mixers[5]; /* should be identical size
286 * with spec
287 */
Kailang Yangdf694da2005-12-05 19:42:22 +0100288 const struct hda_verb *init_verbs[5];
289 unsigned int num_dacs;
290 hda_nid_t *dac_nids;
291 hda_nid_t dig_out_nid; /* optional */
292 hda_nid_t hp_nid; /* optional */
293 unsigned int num_adc_nids;
294 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100295 hda_nid_t *capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100296 hda_nid_t dig_in_nid;
297 unsigned int num_channel_mode;
298 const struct hda_channel_mode *channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200299 int need_dac_fix;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200300 unsigned int num_mux_defs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100301 const struct hda_input_mux *input_mux;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100302 void (*unsol_event)(struct hda_codec *, unsigned int);
303 void (*init_hook)(struct hda_codec *);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200304#ifdef CONFIG_SND_HDA_POWER_SAVE
305 struct hda_amp_list *loopbacks;
306#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307};
308
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309
310/*
311 * input MUX handling
312 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200313static int alc_mux_enum_info(struct snd_kcontrol *kcontrol,
314 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315{
316 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
317 struct alc_spec *spec = codec->spec;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200318 unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id);
319 if (mux_idx >= spec->num_mux_defs)
320 mux_idx = 0;
321 return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322}
323
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200324static int alc_mux_enum_get(struct snd_kcontrol *kcontrol,
325 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326{
327 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
328 struct alc_spec *spec = codec->spec;
329 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
330
331 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
332 return 0;
333}
334
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200335static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
336 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337{
338 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
339 struct alc_spec *spec = codec->spec;
340 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200341 unsigned int mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
Takashi Iwaie1406342008-02-11 18:32:32 +0100342 hda_nid_t nid = spec->capsrc_nids ?
343 spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200344 return snd_hda_input_mux_put(codec, &spec->input_mux[mux_idx], ucontrol,
Takashi Iwaie1406342008-02-11 18:32:32 +0100345 nid, &spec->cur_mux[adc_idx]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346}
347
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200348
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349/*
350 * channel mode setting
351 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200352static int alc_ch_mode_info(struct snd_kcontrol *kcontrol,
353 struct snd_ctl_elem_info *uinfo)
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_info(codec, uinfo, spec->channel_mode,
358 spec->num_channel_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359}
360
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200361static int alc_ch_mode_get(struct snd_kcontrol *kcontrol,
362 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363{
364 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
365 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100366 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200367 spec->num_channel_mode,
368 spec->multiout.max_channels);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369}
370
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200371static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
372 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373{
374 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
375 struct alc_spec *spec = codec->spec;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200376 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
377 spec->num_channel_mode,
378 &spec->multiout.max_channels);
Takashi Iwaibd2033f2006-10-10 19:49:31 +0200379 if (err >= 0 && spec->need_dac_fix)
Takashi Iwai4e195a72006-07-28 14:47:34 +0200380 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
381 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382}
383
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384/*
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100385 * Control the mode of pin widget settings via the mixer. "pc" is used
386 * instead of "%" to avoid consequences of accidently treating the % as
387 * being part of a format specifier. Maximum allowed length of a value is
388 * 63 characters plus NULL terminator.
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100389 *
390 * Note: some retasking pin complexes seem to ignore requests for input
391 * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these
392 * are requested. Therefore order this list so that this behaviour will not
393 * cause problems when mixer clients move through the enum sequentially.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200394 * NIDs 0x0f and 0x10 have been observed to have this behaviour as of
395 * March 2006.
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200396 */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100397static char *alc_pin_mode_names[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100398 "Mic 50pc bias", "Mic 80pc bias",
399 "Line in", "Line out", "Headphone out",
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100400};
401static unsigned char alc_pin_mode_values[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100402 PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100403};
404/* The control can present all 5 options, or it can limit the options based
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200405 * in the pin being assumed to be exclusively an input or an output pin. In
406 * addition, "input" pins may or may not process the mic bias option
407 * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to
408 * accept requests for bias as of chip versions up to March 2006) and/or
409 * wiring in the computer.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100410 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200411#define ALC_PIN_DIR_IN 0x00
412#define ALC_PIN_DIR_OUT 0x01
413#define ALC_PIN_DIR_INOUT 0x02
414#define ALC_PIN_DIR_IN_NOMICBIAS 0x03
415#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100416
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200417/* Info about the pin modes supported by the different pin direction modes.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100418 * For each direction the minimum and maximum values are given.
419 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200420static signed char alc_pin_mode_dir_info[5][2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100421 { 0, 2 }, /* ALC_PIN_DIR_IN */
422 { 3, 4 }, /* ALC_PIN_DIR_OUT */
423 { 0, 4 }, /* ALC_PIN_DIR_INOUT */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200424 { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */
425 { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100426};
427#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0])
428#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1])
429#define alc_pin_mode_n_items(_dir) \
430 (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1)
431
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200432static int alc_pin_mode_info(struct snd_kcontrol *kcontrol,
433 struct snd_ctl_elem_info *uinfo)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200434{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100435 unsigned int item_num = uinfo->value.enumerated.item;
436 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
437
438 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200439 uinfo->count = 1;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100440 uinfo->value.enumerated.items = alc_pin_mode_n_items(dir);
441
442 if (item_num<alc_pin_mode_min(dir) || item_num>alc_pin_mode_max(dir))
443 item_num = alc_pin_mode_min(dir);
444 strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200445 return 0;
446}
447
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200448static int alc_pin_mode_get(struct snd_kcontrol *kcontrol,
449 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200450{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100451 unsigned int i;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200452 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
453 hda_nid_t nid = kcontrol->private_value & 0xffff;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100454 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200455 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200456 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
457 AC_VERB_GET_PIN_WIDGET_CONTROL,
458 0x00);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200459
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100460 /* Find enumerated value for current pinctl setting */
461 i = alc_pin_mode_min(dir);
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200462 while (alc_pin_mode_values[i] != pinctl && i <= alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100463 i++;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200464 *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100465 return 0;
466}
467
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200468static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
469 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100470{
471 signed int change;
472 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
473 hda_nid_t nid = kcontrol->private_value & 0xffff;
474 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
475 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200476 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
477 AC_VERB_GET_PIN_WIDGET_CONTROL,
478 0x00);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100479
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200480 if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100481 val = alc_pin_mode_min(dir);
482
483 change = pinctl != alc_pin_mode_values[val];
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100484 if (change) {
485 /* Set pin mode to that requested */
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200486 snd_hda_codec_write_cache(codec, nid, 0,
487 AC_VERB_SET_PIN_WIDGET_CONTROL,
488 alc_pin_mode_values[val]);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100489
490 /* Also enable the retasking pin's input/output as required
491 * for the requested pin mode. Enum values of 2 or less are
492 * input modes.
493 *
494 * Dynamically switching the input/output buffers probably
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200495 * reduces noise slightly (particularly on input) so we'll
496 * do it. However, having both input and output buffers
497 * enabled simultaneously doesn't seem to be problematic if
498 * this turns out to be necessary in the future.
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100499 */
500 if (val <= 2) {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200501 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
502 HDA_AMP_MUTE, HDA_AMP_MUTE);
503 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
504 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100505 } else {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200506 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
507 HDA_AMP_MUTE, HDA_AMP_MUTE);
508 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
509 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100510 }
511 }
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200512 return change;
513}
514
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100515#define ALC_PIN_MODE(xname, nid, dir) \
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200516 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100517 .info = alc_pin_mode_info, \
518 .get = alc_pin_mode_get, \
519 .put = alc_pin_mode_put, \
520 .private_value = nid | (dir<<16) }
Kailang Yangdf694da2005-12-05 19:42:22 +0100521
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100522/* A switch control for ALC260 GPIO pins. Multiple GPIOs can be ganged
523 * together using a mask with more than one bit set. This control is
524 * currently used only by the ALC260 test model. At this stage they are not
525 * needed for any "production" models.
526 */
527#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200528#define alc_gpio_data_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200529
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200530static int alc_gpio_data_get(struct snd_kcontrol *kcontrol,
531 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100532{
533 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
534 hda_nid_t nid = kcontrol->private_value & 0xffff;
535 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
536 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200537 unsigned int val = snd_hda_codec_read(codec, nid, 0,
538 AC_VERB_GET_GPIO_DATA, 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100539
540 *valp = (val & mask) != 0;
541 return 0;
542}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200543static int alc_gpio_data_put(struct snd_kcontrol *kcontrol,
544 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100545{
546 signed int change;
547 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
548 hda_nid_t nid = kcontrol->private_value & 0xffff;
549 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
550 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200551 unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0,
552 AC_VERB_GET_GPIO_DATA,
553 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100554
555 /* Set/unset the masked GPIO bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200556 change = (val == 0 ? 0 : mask) != (gpio_data & mask);
557 if (val == 0)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100558 gpio_data &= ~mask;
559 else
560 gpio_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200561 snd_hda_codec_write_cache(codec, nid, 0,
562 AC_VERB_SET_GPIO_DATA, gpio_data);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100563
564 return change;
565}
566#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
567 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
568 .info = alc_gpio_data_info, \
569 .get = alc_gpio_data_get, \
570 .put = alc_gpio_data_put, \
571 .private_value = nid | (mask<<16) }
572#endif /* CONFIG_SND_DEBUG */
573
Jonathan Woithe92621f12006-02-28 11:47:47 +0100574/* A switch control to allow the enabling of the digital IO pins on the
575 * ALC260. This is incredibly simplistic; the intention of this control is
576 * to provide something in the test model allowing digital outputs to be
577 * identified if present. If models are found which can utilise these
578 * outputs a more complete mixer control can be devised for those models if
579 * necessary.
580 */
581#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200582#define alc_spdif_ctrl_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200583
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200584static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol,
585 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100586{
587 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
588 hda_nid_t nid = kcontrol->private_value & 0xffff;
589 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
590 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200591 unsigned int val = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100592 AC_VERB_GET_DIGI_CONVERT_1, 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100593
594 *valp = (val & mask) != 0;
595 return 0;
596}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200597static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
598 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100599{
600 signed int change;
601 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
602 hda_nid_t nid = kcontrol->private_value & 0xffff;
603 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
604 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200605 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100606 AC_VERB_GET_DIGI_CONVERT_1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200607 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100608
609 /* Set/unset the masked control bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200610 change = (val == 0 ? 0 : mask) != (ctrl_data & mask);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100611 if (val==0)
612 ctrl_data &= ~mask;
613 else
614 ctrl_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200615 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
616 ctrl_data);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100617
618 return change;
619}
620#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \
621 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
622 .info = alc_spdif_ctrl_info, \
623 .get = alc_spdif_ctrl_get, \
624 .put = alc_spdif_ctrl_put, \
625 .private_value = nid | (mask<<16) }
626#endif /* CONFIG_SND_DEBUG */
627
Jonathan Woithef8225f62008-01-08 12:16:54 +0100628/* A switch control to allow the enabling EAPD digital outputs on the ALC26x.
629 * Again, this is only used in the ALC26x test models to help identify when
630 * the EAPD line must be asserted for features to work.
631 */
632#ifdef CONFIG_SND_DEBUG
633#define alc_eapd_ctrl_info snd_ctl_boolean_mono_info
634
635static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol,
636 struct snd_ctl_elem_value *ucontrol)
637{
638 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
639 hda_nid_t nid = kcontrol->private_value & 0xffff;
640 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
641 long *valp = ucontrol->value.integer.value;
642 unsigned int val = snd_hda_codec_read(codec, nid, 0,
643 AC_VERB_GET_EAPD_BTLENABLE, 0x00);
644
645 *valp = (val & mask) != 0;
646 return 0;
647}
648
649static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
650 struct snd_ctl_elem_value *ucontrol)
651{
652 int change;
653 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
654 hda_nid_t nid = kcontrol->private_value & 0xffff;
655 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
656 long val = *ucontrol->value.integer.value;
657 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
658 AC_VERB_GET_EAPD_BTLENABLE,
659 0x00);
660
661 /* Set/unset the masked control bit(s) as needed */
662 change = (!val ? 0 : mask) != (ctrl_data & mask);
663 if (!val)
664 ctrl_data &= ~mask;
665 else
666 ctrl_data |= mask;
667 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
668 ctrl_data);
669
670 return change;
671}
672
673#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \
674 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
675 .info = alc_eapd_ctrl_info, \
676 .get = alc_eapd_ctrl_get, \
677 .put = alc_eapd_ctrl_put, \
678 .private_value = nid | (mask<<16) }
679#endif /* CONFIG_SND_DEBUG */
680
Kailang Yangdf694da2005-12-05 19:42:22 +0100681/*
682 * set up from the preset table
683 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200684static void setup_preset(struct alc_spec *spec,
685 const struct alc_config_preset *preset)
Kailang Yangdf694da2005-12-05 19:42:22 +0100686{
687 int i;
688
689 for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
690 spec->mixers[spec->num_mixers++] = preset->mixers[i];
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200691 for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i];
692 i++)
693 spec->init_verbs[spec->num_init_verbs++] =
694 preset->init_verbs[i];
Kailang Yangdf694da2005-12-05 19:42:22 +0100695
696 spec->channel_mode = preset->channel_mode;
697 spec->num_channel_mode = preset->num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200698 spec->need_dac_fix = preset->need_dac_fix;
Kailang Yangdf694da2005-12-05 19:42:22 +0100699
700 spec->multiout.max_channels = spec->channel_mode[0].channels;
701
702 spec->multiout.num_dacs = preset->num_dacs;
703 spec->multiout.dac_nids = preset->dac_nids;
704 spec->multiout.dig_out_nid = preset->dig_out_nid;
705 spec->multiout.hp_nid = preset->hp_nid;
706
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200707 spec->num_mux_defs = preset->num_mux_defs;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200708 if (!spec->num_mux_defs)
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200709 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +0100710 spec->input_mux = preset->input_mux;
711
712 spec->num_adc_nids = preset->num_adc_nids;
713 spec->adc_nids = preset->adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100714 spec->capsrc_nids = preset->capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100715 spec->dig_in_nid = preset->dig_in_nid;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100716
717 spec->unsol_event = preset->unsol_event;
718 spec->init_hook = preset->init_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200719#ifdef CONFIG_SND_HDA_POWER_SAVE
720 spec->loopback.amplist = preset->loopbacks;
721#endif
Kailang Yangdf694da2005-12-05 19:42:22 +0100722}
723
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200724/* Enable GPIO mask and set output */
725static struct hda_verb alc_gpio1_init_verbs[] = {
726 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
727 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
728 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
729 { }
730};
731
732static struct hda_verb alc_gpio2_init_verbs[] = {
733 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
734 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
735 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
736 { }
737};
738
Kailang Yangbdd148a2007-05-08 15:19:08 +0200739static struct hda_verb alc_gpio3_init_verbs[] = {
740 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
741 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
742 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
743 { }
744};
745
Kailang Yangc9b58002007-10-16 14:30:01 +0200746static void alc_sku_automute(struct hda_codec *codec)
747{
748 struct alc_spec *spec = codec->spec;
Kailang Yangc9b58002007-10-16 14:30:01 +0200749 unsigned int present;
750 unsigned int hp_nid = spec->autocfg.hp_pins[0];
751 unsigned int sp_nid = spec->autocfg.speaker_pins[0];
752
753 /* need to execute and sync at first */
754 snd_hda_codec_read(codec, hp_nid, 0, AC_VERB_SET_PIN_SENSE, 0);
755 present = snd_hda_codec_read(codec, hp_nid, 0,
756 AC_VERB_GET_PIN_SENSE, 0);
757 spec->jack_present = (present & 0x80000000) != 0;
Takashi Iwaif6c7e542008-02-12 18:32:23 +0100758 snd_hda_codec_write(codec, sp_nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
759 spec->jack_present ? 0 : PIN_OUT);
Kailang Yangc9b58002007-10-16 14:30:01 +0200760}
761
762/* unsolicited event for HP jack sensing */
763static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
764{
765 if (codec->vendor_id == 0x10ec0880)
766 res >>= 28;
767 else
768 res >>= 26;
769 if (res != ALC880_HP_EVENT)
770 return;
771
772 alc_sku_automute(codec);
773}
774
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200775/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
776 * 31 ~ 16 : Manufacture ID
777 * 15 ~ 8 : SKU ID
778 * 7 ~ 0 : Assembly ID
779 * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
780 */
781static void alc_subsystem_id(struct hda_codec *codec,
782 unsigned int porta, unsigned int porte,
783 unsigned int portd)
784{
Kailang Yangc9b58002007-10-16 14:30:01 +0200785 unsigned int ass, tmp, i;
786 unsigned nid;
787 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200788
Kailang Yangc9b58002007-10-16 14:30:01 +0200789 ass = codec->subsystem_id & 0xffff;
790 if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
791 goto do_sku;
792
793 /*
794 * 31~30 : port conetcivity
795 * 29~21 : reserve
796 * 20 : PCBEEP input
797 * 19~16 : Check sum (15:1)
798 * 15~1 : Custom
799 * 0 : override
800 */
801 nid = 0x1d;
802 if (codec->vendor_id == 0x10ec0260)
803 nid = 0x17;
804 ass = snd_hda_codec_read(codec, nid, 0,
805 AC_VERB_GET_CONFIG_DEFAULT, 0);
806 if (!(ass & 1) && !(ass & 0x100000))
807 return;
808 if ((ass >> 30) != 1) /* no physical connection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200809 return;
810
Kailang Yangc9b58002007-10-16 14:30:01 +0200811 /* check sum */
812 tmp = 0;
813 for (i = 1; i < 16; i++) {
Kailang Yang8c427222008-01-10 13:03:59 +0100814 if ((ass >> i) & 1)
Kailang Yangc9b58002007-10-16 14:30:01 +0200815 tmp++;
816 }
817 if (((ass >> 16) & 0xf) != tmp)
818 return;
819do_sku:
820 /*
821 * 0 : override
822 * 1 : Swap Jack
823 * 2 : 0 --> Desktop, 1 --> Laptop
824 * 3~5 : External Amplifier control
825 * 7~6 : Reserved
826 */
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200827 tmp = (ass & 0x38) >> 3; /* external Amp control */
828 switch (tmp) {
829 case 1:
830 snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
831 break;
832 case 3:
833 snd_hda_sequence_write(codec, alc_gpio2_init_verbs);
834 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +0200835 case 7:
836 snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
837 break;
Kailang Yangc9b58002007-10-16 14:30:01 +0200838 case 5: /* set EAPD output high */
Kailang Yangbdd148a2007-05-08 15:19:08 +0200839 switch (codec->vendor_id) {
Kailang Yangc9b58002007-10-16 14:30:01 +0200840 case 0x10ec0260:
841 snd_hda_codec_write(codec, 0x0f, 0,
842 AC_VERB_SET_EAPD_BTLENABLE, 2);
843 snd_hda_codec_write(codec, 0x10, 0,
844 AC_VERB_SET_EAPD_BTLENABLE, 2);
845 break;
846 case 0x10ec0262:
Kailang Yangbdd148a2007-05-08 15:19:08 +0200847 case 0x10ec0267:
848 case 0x10ec0268:
Kailang Yangc9b58002007-10-16 14:30:01 +0200849 case 0x10ec0269:
850 case 0x10ec0862:
851 case 0x10ec0662:
Kailang Yangbdd148a2007-05-08 15:19:08 +0200852 snd_hda_codec_write(codec, 0x14, 0,
853 AC_VERB_SET_EAPD_BTLENABLE, 2);
854 snd_hda_codec_write(codec, 0x15, 0,
855 AC_VERB_SET_EAPD_BTLENABLE, 2);
Kailang Yangc9b58002007-10-16 14:30:01 +0200856 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +0200857 }
Kailang Yangc9b58002007-10-16 14:30:01 +0200858 switch (codec->vendor_id) {
859 case 0x10ec0260:
860 snd_hda_codec_write(codec, 0x1a, 0,
861 AC_VERB_SET_COEF_INDEX, 7);
862 tmp = snd_hda_codec_read(codec, 0x1a, 0,
863 AC_VERB_GET_PROC_COEF, 0);
864 snd_hda_codec_write(codec, 0x1a, 0,
865 AC_VERB_SET_COEF_INDEX, 7);
866 snd_hda_codec_write(codec, 0x1a, 0,
867 AC_VERB_SET_PROC_COEF,
868 tmp | 0x2010);
869 break;
870 case 0x10ec0262:
871 case 0x10ec0880:
872 case 0x10ec0882:
873 case 0x10ec0883:
874 case 0x10ec0885:
875 case 0x10ec0888:
876 snd_hda_codec_write(codec, 0x20, 0,
877 AC_VERB_SET_COEF_INDEX, 7);
878 tmp = snd_hda_codec_read(codec, 0x20, 0,
879 AC_VERB_GET_PROC_COEF, 0);
880 snd_hda_codec_write(codec, 0x20, 0,
881 AC_VERB_SET_COEF_INDEX, 7);
882 snd_hda_codec_write(codec, 0x20, 0,
883 AC_VERB_SET_PROC_COEF,
884 tmp | 0x2010);
885 break;
886 case 0x10ec0267:
887 case 0x10ec0268:
888 snd_hda_codec_write(codec, 0x20, 0,
889 AC_VERB_SET_COEF_INDEX, 7);
890 tmp = snd_hda_codec_read(codec, 0x20, 0,
891 AC_VERB_GET_PROC_COEF, 0);
892 snd_hda_codec_write(codec, 0x20, 0,
893 AC_VERB_SET_COEF_INDEX, 7);
894 snd_hda_codec_write(codec, 0x20, 0,
895 AC_VERB_SET_PROC_COEF,
896 tmp | 0x3000);
897 break;
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200898 }
Kailang Yangc9b58002007-10-16 14:30:01 +0200899 default:
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200900 break;
901 }
Kailang Yangc9b58002007-10-16 14:30:01 +0200902
Kailang Yang8c427222008-01-10 13:03:59 +0100903 /* is laptop or Desktop and enable the function "Mute internal speaker
Kailang Yangc9b58002007-10-16 14:30:01 +0200904 * when the external headphone out jack is plugged"
905 */
Kailang Yang8c427222008-01-10 13:03:59 +0100906 if (!(ass & 0x8000))
Kailang Yangc9b58002007-10-16 14:30:01 +0200907 return;
908 /*
909 * 10~8 : Jack location
910 * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
911 * 14~13: Resvered
912 * 15 : 1 --> enable the function "Mute internal speaker
913 * when the external headphone out jack is plugged"
914 */
915 if (!spec->autocfg.speaker_pins[0]) {
Kailang Yang8c427222008-01-10 13:03:59 +0100916 if (spec->autocfg.line_out_pins[0])
Kailang Yangc9b58002007-10-16 14:30:01 +0200917 spec->autocfg.speaker_pins[0] =
Kailang Yang8c427222008-01-10 13:03:59 +0100918 spec->autocfg.line_out_pins[0];
Kailang Yangc9b58002007-10-16 14:30:01 +0200919 else
920 return;
921 }
922
923 if (!spec->autocfg.hp_pins[0]) {
924 tmp = (ass >> 11) & 0x3; /* HP to chassis */
925 if (tmp == 0)
926 spec->autocfg.hp_pins[0] = porta;
927 else if (tmp == 1)
928 spec->autocfg.hp_pins[0] = porte;
929 else if (tmp == 2)
930 spec->autocfg.hp_pins[0] = portd;
931 else
932 return;
933 }
934
935 snd_hda_codec_write(codec, spec->autocfg.hp_pins[0], 0,
936 AC_VERB_SET_UNSOLICITED_ENABLE,
937 AC_USRSP_EN | ALC880_HP_EVENT);
938 spec->unsol_event = alc_sku_unsol_event;
939 spec->init_hook = alc_sku_automute;
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200940}
941
Takashi Iwai41e41f12005-06-08 14:48:49 +0200942/*
Takashi Iwaif95474e2007-07-10 00:47:43 +0200943 * Fix-up pin default configurations
944 */
945
946struct alc_pincfg {
947 hda_nid_t nid;
948 u32 val;
949};
950
951static void alc_fix_pincfg(struct hda_codec *codec,
952 const struct snd_pci_quirk *quirk,
953 const struct alc_pincfg **pinfix)
954{
955 const struct alc_pincfg *cfg;
956
957 quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
958 if (!quirk)
959 return;
960
961 cfg = pinfix[quirk->value];
962 for (; cfg->nid; cfg++) {
963 int i;
964 u32 val = cfg->val;
965 for (i = 0; i < 4; i++) {
966 snd_hda_codec_write(codec, cfg->nid, 0,
967 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 + i,
968 val & 0xff);
969 val >>= 8;
970 }
971 }
972}
973
974/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200975 * ALC880 3-stack model
976 *
977 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200978 * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18,
979 * F-Mic = 0x1b, HP = 0x19
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 */
981
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200982static hda_nid_t alc880_dac_nids[4] = {
983 /* front, rear, clfe, rear_surr */
984 0x02, 0x05, 0x04, 0x03
985};
986
987static hda_nid_t alc880_adc_nids[3] = {
988 /* ADC0-2 */
989 0x07, 0x08, 0x09,
990};
991
992/* The datasheet says the node 0x07 is connected from inputs,
993 * but it shows zero connection in the real implementation on some devices.
Kailang Yangdf694da2005-12-05 19:42:22 +0100994 * Note: this is a 915GAV bug, fixed on 915GLV
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200996static hda_nid_t alc880_adc_nids_alt[2] = {
997 /* ADC1-2 */
998 0x08, 0x09,
999};
1000
1001#define ALC880_DIGOUT_NID 0x06
1002#define ALC880_DIGIN_NID 0x0a
1003
1004static struct hda_input_mux alc880_capture_source = {
1005 .num_items = 4,
1006 .items = {
1007 { "Mic", 0x0 },
1008 { "Front Mic", 0x3 },
1009 { "Line", 0x2 },
1010 { "CD", 0x4 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001012};
1013
1014/* channel source setting (2/6 channel selection for 3-stack) */
1015/* 2ch mode */
1016static struct hda_verb alc880_threestack_ch2_init[] = {
1017 /* set line-in to input, mute it */
1018 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1019 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1020 /* set mic-in to input vref 80%, mute it */
1021 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1022 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 { } /* end */
1024};
1025
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001026/* 6ch mode */
1027static struct hda_verb alc880_threestack_ch6_init[] = {
1028 /* set line-in to output, unmute it */
1029 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1030 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1031 /* set mic-in to output, unmute it */
1032 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1033 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1034 { } /* end */
1035};
1036
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001037static struct hda_channel_mode alc880_threestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001038 { 2, alc880_threestack_ch2_init },
1039 { 6, alc880_threestack_ch6_init },
1040};
1041
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001042static struct snd_kcontrol_new alc880_three_stack_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02001043 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001044 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02001045 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001046 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02001047 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1048 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001049 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1050 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1052 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1053 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1054 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1055 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1056 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1057 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
1058 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
1059 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1060 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001062 {
1063 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1064 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001065 .info = alc_ch_mode_info,
1066 .get = alc_ch_mode_get,
1067 .put = alc_ch_mode_put,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001068 },
1069 { } /* end */
1070};
1071
1072/* capture mixer elements */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001073static struct snd_kcontrol_new alc880_capture_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001074 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
1075 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
1076 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
1077 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
1078 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
1079 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
1080 {
1081 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1082 /* The multiple "Capture Source" controls confuse alsamixer
1083 * So call somewhat different..
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001084 */
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..
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 */
1106 /* .name = "Capture Source", */
1107 .name = "Input Source",
1108 .count = 2,
1109 .info = alc_mux_enum_info,
1110 .get = alc_mux_enum_get,
1111 .put = alc_mux_enum_put,
1112 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 { } /* end */
1114};
1115
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001116
1117
1118/*
1119 * ALC880 5-stack model
1120 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001121 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d),
1122 * Side = 0x02 (0xd)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001123 * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
1124 * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
1125 */
1126
1127/* additional mixers to alc880_three_stack_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001128static struct snd_kcontrol_new alc880_five_stack_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001129 HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001130 HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 { } /* end */
1132};
1133
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001134/* channel source setting (6/8 channel selection for 5-stack) */
1135/* 6ch mode */
1136static struct hda_verb alc880_fivestack_ch6_init[] = {
1137 /* set line-in to input, mute it */
1138 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1139 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001140 { } /* end */
1141};
1142
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001143/* 8ch mode */
1144static struct hda_verb alc880_fivestack_ch8_init[] = {
1145 /* set line-in to output, unmute it */
1146 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1147 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1148 { } /* end */
1149};
1150
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001151static struct hda_channel_mode alc880_fivestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001152 { 6, alc880_fivestack_ch6_init },
1153 { 8, alc880_fivestack_ch8_init },
1154};
1155
1156
1157/*
1158 * ALC880 6-stack model
1159 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001160 * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e),
1161 * Side = 0x05 (0x0f)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001162 * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
1163 * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
1164 */
1165
1166static hda_nid_t alc880_6st_dac_nids[4] = {
1167 /* front, rear, clfe, rear_surr */
1168 0x02, 0x03, 0x04, 0x05
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001169};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001170
1171static struct hda_input_mux alc880_6stack_capture_source = {
1172 .num_items = 4,
1173 .items = {
1174 { "Mic", 0x0 },
1175 { "Front Mic", 0x1 },
1176 { "Line", 0x2 },
1177 { "CD", 0x4 },
1178 },
1179};
1180
1181/* fixed 8-channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001182static struct hda_channel_mode alc880_sixstack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001183 { 8, NULL },
1184};
1185
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001186static struct snd_kcontrol_new alc880_six_stack_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001187 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001188 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001189 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001190 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001191 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1192 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001193 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1194 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001195 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001196 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001197 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1198 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1199 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1200 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1201 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1202 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1203 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1204 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1205 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1206 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001207 {
1208 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1209 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001210 .info = alc_ch_mode_info,
1211 .get = alc_ch_mode_get,
1212 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02001213 },
1214 { } /* end */
1215};
1216
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001217
1218/*
1219 * ALC880 W810 model
1220 *
1221 * W810 has rear IO for:
1222 * Front (DAC 02)
1223 * Surround (DAC 03)
1224 * Center/LFE (DAC 04)
1225 * Digital out (06)
1226 *
1227 * The system also has a pair of internal speakers, and a headphone jack.
1228 * These are both connected to Line2 on the codec, hence to DAC 02.
1229 *
1230 * There is a variable resistor to control the speaker or headphone
1231 * volume. This is a hardware-only device without a software API.
1232 *
1233 * Plugging headphones in will disable the internal speakers. This is
1234 * implemented in hardware, not via the driver using jack sense. In
1235 * a similar fashion, plugging into the rear socket marked "front" will
1236 * disable both the speakers and headphones.
1237 *
1238 * For input, there's a microphone jack, and an "audio in" jack.
1239 * These may not do anything useful with this driver yet, because I
1240 * haven't setup any initialization verbs for these yet...
1241 */
1242
1243static hda_nid_t alc880_w810_dac_nids[3] = {
1244 /* front, rear/surround, clfe */
1245 0x02, 0x03, 0x04
1246};
1247
1248/* fixed 6 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001249static struct hda_channel_mode alc880_w810_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001250 { 6, NULL }
1251};
1252
1253/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001254static struct snd_kcontrol_new alc880_w810_base_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001255 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001256 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001257 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001258 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001259 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1260 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001261 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1262 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001263 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1264 { } /* end */
1265};
1266
1267
1268/*
1269 * Z710V model
1270 *
1271 * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001272 * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?),
1273 * Line = 0x1a
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001274 */
1275
1276static hda_nid_t alc880_z71v_dac_nids[1] = {
1277 0x02
1278};
1279#define ALC880_Z71V_HP_DAC 0x03
1280
1281/* fixed 2 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001282static struct hda_channel_mode alc880_2_jack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001283 { 2, NULL }
1284};
1285
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001286static struct snd_kcontrol_new alc880_z71v_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001287 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001288 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001289 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001290 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001291 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1292 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1293 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1294 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1295 { } /* end */
1296};
1297
1298
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001299/*
1300 * ALC880 F1734 model
1301 *
1302 * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
1303 * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
1304 */
1305
1306static hda_nid_t alc880_f1734_dac_nids[1] = {
1307 0x03
1308};
1309#define ALC880_F1734_HP_DAC 0x02
1310
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001311static struct snd_kcontrol_new alc880_f1734_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001312 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001313 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01001314 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1315 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001316 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1317 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai937b4162008-02-11 14:52:36 +01001318 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1319 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001320 { } /* end */
1321};
1322
Takashi Iwai937b4162008-02-11 14:52:36 +01001323static struct hda_input_mux alc880_f1734_capture_source = {
1324 .num_items = 2,
1325 .items = {
1326 { "Mic", 0x1 },
1327 { "CD", 0x4 },
1328 },
1329};
1330
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001331
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001332/*
1333 * ALC880 ASUS model
1334 *
1335 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
1336 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
1337 * Mic = 0x18, Line = 0x1a
1338 */
1339
1340#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */
1341#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */
1342
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001343static struct snd_kcontrol_new alc880_asus_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001344 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001345 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001346 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001347 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001348 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1349 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001350 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1351 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001352 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1353 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1354 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1355 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1356 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1357 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001358 {
1359 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1360 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001361 .info = alc_ch_mode_info,
1362 .get = alc_ch_mode_get,
1363 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02001364 },
1365 { } /* end */
1366};
1367
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001368/*
1369 * ALC880 ASUS W1V model
1370 *
1371 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
1372 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
1373 * Mic = 0x18, Line = 0x1a, Line2 = 0x1b
1374 */
1375
1376/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001377static struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001378 HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
1379 HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001380 { } /* end */
1381};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001382
Takashi Iwai3c10a9d2005-08-23 20:02:27 +02001383/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001384static struct snd_kcontrol_new alc880_pcbeep_mixer[] = {
Takashi Iwai3c10a9d2005-08-23 20:02:27 +02001385 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1386 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
1387 { } /* end */
1388};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001389
Kailang Yangdf694da2005-12-05 19:42:22 +01001390/* TCL S700 */
1391static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
1392 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1393 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1394 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
1395 HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT),
1396 HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT),
1397 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT),
1398 HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT),
1399 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
1400 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
1401 {
1402 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1403 /* The multiple "Capture Source" controls confuse alsamixer
1404 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01001405 */
1406 /* .name = "Capture Source", */
1407 .name = "Input Source",
1408 .count = 1,
1409 .info = alc_mux_enum_info,
1410 .get = alc_mux_enum_get,
1411 .put = alc_mux_enum_put,
1412 },
1413 { } /* end */
1414};
1415
Kailang Yangccc656c2006-10-17 12:32:26 +02001416/* Uniwill */
1417static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01001418 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1419 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1420 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1421 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02001422 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1423 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
1424 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1425 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
1426 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1427 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1428 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1429 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1430 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1431 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1432 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1433 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1434 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1435 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
1436 {
1437 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1438 .name = "Channel Mode",
1439 .info = alc_ch_mode_info,
1440 .get = alc_ch_mode_get,
1441 .put = alc_ch_mode_put,
1442 },
1443 { } /* end */
1444};
1445
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01001446static struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
1447 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1448 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1449 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1450 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
1451 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1452 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1453 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1454 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1455 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1456 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1457 { } /* end */
1458};
1459
Kailang Yangccc656c2006-10-17 12:32:26 +02001460static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01001461 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1462 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1463 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1464 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02001465 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1466 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1467 { } /* end */
1468};
1469
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470/*
Takashi Iwai2134ea42008-01-10 16:53:55 +01001471 * virtual master controls
1472 */
1473
1474/*
1475 * slave controls for virtual master
1476 */
1477static const char *alc_slave_vols[] = {
1478 "Front Playback Volume",
1479 "Surround Playback Volume",
1480 "Center Playback Volume",
1481 "LFE Playback Volume",
1482 "Side Playback Volume",
1483 "Headphone Playback Volume",
1484 "Speaker Playback Volume",
1485 "Mono Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001486 "Line-Out Playback Volume",
1487 NULL,
1488};
1489
1490static const char *alc_slave_sws[] = {
1491 "Front Playback Switch",
1492 "Surround Playback Switch",
1493 "Center Playback Switch",
1494 "LFE Playback Switch",
1495 "Side Playback Switch",
1496 "Headphone Playback Switch",
1497 "Speaker Playback Switch",
1498 "Mono Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01001499 "IEC958 Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001500 NULL,
1501};
1502
1503/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001504 * build control elements
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 */
1506static int alc_build_controls(struct hda_codec *codec)
1507{
1508 struct alc_spec *spec = codec->spec;
1509 int err;
1510 int i;
1511
1512 for (i = 0; i < spec->num_mixers; i++) {
1513 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
1514 if (err < 0)
1515 return err;
1516 }
1517
1518 if (spec->multiout.dig_out_nid) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001519 err = snd_hda_create_spdif_out_ctls(codec,
1520 spec->multiout.dig_out_nid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 if (err < 0)
1522 return err;
Takashi Iwai9a081602008-02-12 18:37:26 +01001523 err = snd_hda_create_spdif_share_sw(codec,
1524 &spec->multiout);
1525 if (err < 0)
1526 return err;
1527 spec->multiout.share_spdif = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 }
1529 if (spec->dig_in_nid) {
1530 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
1531 if (err < 0)
1532 return err;
1533 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01001534
1535 /* if we have no master control, let's create it */
1536 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
1537 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
1538 HDA_OUTPUT, spec->vmaster_tlv);
1539 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
1540 spec->vmaster_tlv, alc_slave_vols);
1541 if (err < 0)
1542 return err;
1543 }
1544 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
1545 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
1546 NULL, alc_slave_sws);
1547 if (err < 0)
1548 return err;
1549 }
1550
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 return 0;
1552}
1553
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001554
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555/*
1556 * initialize the codec volumes, etc
1557 */
1558
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001559/*
1560 * generic initialization of ADC, input mixers and output mixers
1561 */
1562static struct hda_verb alc880_volume_init_verbs[] = {
1563 /*
1564 * Unmute ADC0-2 and set the default input to mic-in
1565 */
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001566 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001567 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001568 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001569 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001570 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001571 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001573 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
1574 * mixer widget
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001575 * Note: PASD motherboards uses the Line In 2 as the input for front
1576 * panel mic (mic 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001578 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02001579 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1580 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1581 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
1582 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
1583 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
1584 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
1585 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001587 /*
1588 * Set up output mixers (0x0c - 0x0f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001590 /* set vol=0 to output mixers */
1591 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1592 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1593 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1594 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1595 /* set up input amps for analog loopback */
1596 /* Amp Indices: DAC = 0, mixer = 1 */
Takashi Iwai05acb862005-06-10 19:50:25 +02001597 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1598 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02001599 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1600 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02001601 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1602 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02001603 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1604 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605
1606 { }
1607};
1608
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001609/*
1610 * 3-stack pin configuration:
1611 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
1612 */
1613static struct hda_verb alc880_pin_3stack_init_verbs[] = {
1614 /*
1615 * preset connection lists of input pins
1616 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
1617 */
1618 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
1619 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1620 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
1621
1622 /*
1623 * Set pin mode and muting
1624 */
1625 /* set front pin widgets 0x14 for output */
1626 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1627 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1628 /* Mic1 (rear panel) pin widget for input and vref at 80% */
1629 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1630 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1631 /* Mic2 (as headphone out) for HP output */
1632 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1633 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1634 /* Line In pin widget for input */
1635 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1636 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1637 /* Line2 (as front mic) pin widget for input and vref at 80% */
1638 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1639 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1640 /* CD pin widget for input */
1641 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1642
1643 { }
1644};
1645
1646/*
1647 * 5-stack pin configuration:
1648 * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
1649 * line-in/side = 0x1a, f-mic = 0x1b
1650 */
1651static struct hda_verb alc880_pin_5stack_init_verbs[] = {
1652 /*
1653 * preset connection lists of input pins
1654 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
1655 */
1656 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1657 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
1658
1659 /*
1660 * Set pin mode and muting
1661 */
1662 /* set pin widgets 0x14-0x17 for output */
Takashi Iwai05acb862005-06-10 19:50:25 +02001663 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1664 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1665 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1666 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001667 /* unmute pins for output (no gain on this amp) */
1668 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1669 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1670 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1671 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1672
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02001674 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001675 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1676 /* Mic2 (as headphone out) for HP output */
1677 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02001678 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001679 /* Line In pin widget for input */
1680 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1681 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1682 /* Line2 (as front mic) pin widget for input and vref at 80% */
1683 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1684 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1685 /* CD pin widget for input */
1686 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687
1688 { }
1689};
1690
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001691/*
1692 * W810 pin configuration:
1693 * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
1694 */
1695static struct hda_verb alc880_pin_w810_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 /* hphone/speaker input selector: front DAC */
1697 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
1698
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001699 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1700 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1701 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1702 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1703 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1704 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1705
1706 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02001707 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 { }
1710};
1711
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001712/*
1713 * Z71V pin configuration:
1714 * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
1715 */
1716static struct hda_verb alc880_pin_z71v_init_verbs[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02001717 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001718 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai05acb862005-06-10 19:50:25 +02001719 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001720 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001721
Takashi Iwai16ded522005-06-10 19:58:24 +02001722 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001723 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02001724 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001725 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001726
1727 { }
1728};
1729
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001730/*
1731 * 6-stack pin configuration:
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001732 * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
1733 * f-mic = 0x19, line = 0x1a, HP = 0x1b
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001734 */
1735static struct hda_verb alc880_pin_6stack_init_verbs[] = {
1736 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1737
Takashi Iwai16ded522005-06-10 19:58:24 +02001738 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001739 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001740 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001741 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001742 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001743 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001744 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001745 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1746
Takashi Iwai16ded522005-06-10 19:58:24 +02001747 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001748 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001749 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001750 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001751 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001752 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001753 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai16ded522005-06-10 19:58:24 +02001754 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001755 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1756
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001757 { }
1758};
Takashi Iwai16ded522005-06-10 19:58:24 +02001759
Kailang Yangccc656c2006-10-17 12:32:26 +02001760/*
1761 * Uniwill pin configuration:
1762 * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
1763 * line = 0x1a
1764 */
1765static struct hda_verb alc880_uniwill_init_verbs[] = {
1766 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1767
1768 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1769 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1770 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1771 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1772 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1773 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1774 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1775 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1776 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1777 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1778 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1779 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1780 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1781 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1782
1783 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1784 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1785 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1786 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1787 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1788 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1789 /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
1790 /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
1791 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1792
1793 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
1794 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
1795
1796 { }
1797};
1798
1799/*
1800* Uniwill P53
1801* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
1802 */
1803static struct hda_verb alc880_uniwill_p53_init_verbs[] = {
1804 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1805
1806 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1807 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1808 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1809 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1810 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1811 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1812 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1813 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1814 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1815 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1816 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1817 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1818
1819 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1820 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1821 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1822 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1823 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1824 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1825
1826 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
1827 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT},
1828
1829 { }
1830};
1831
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01001832static struct hda_verb alc880_beep_init_verbs[] = {
1833 { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
1834 { }
1835};
1836
Kailang Yangccc656c2006-10-17 12:32:26 +02001837/* toggle speaker-output according to the hp-jack state */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02001838static void alc880_uniwill_hp_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02001839{
1840 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001841 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02001842
1843 present = snd_hda_codec_read(codec, 0x14, 0,
1844 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02001845 bits = present ? HDA_AMP_MUTE : 0;
1846 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
1847 HDA_AMP_MUTE, bits);
1848 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
1849 HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02001850}
1851
1852/* auto-toggle front mic */
1853static void alc880_uniwill_mic_automute(struct hda_codec *codec)
1854{
1855 unsigned int present;
1856 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02001857
1858 present = snd_hda_codec_read(codec, 0x18, 0,
1859 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02001860 bits = present ? HDA_AMP_MUTE : 0;
1861 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02001862}
1863
1864static void alc880_uniwill_automute(struct hda_codec *codec)
1865{
1866 alc880_uniwill_hp_automute(codec);
1867 alc880_uniwill_mic_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02001868}
1869
1870static void alc880_uniwill_unsol_event(struct hda_codec *codec,
1871 unsigned int res)
1872{
1873 /* Looks like the unsol event is incompatible with the standard
1874 * definition. 4bit tag is placed at 28 bit!
1875 */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02001876 switch (res >> 28) {
1877 case ALC880_HP_EVENT:
1878 alc880_uniwill_hp_automute(codec);
1879 break;
1880 case ALC880_MIC_EVENT:
1881 alc880_uniwill_mic_automute(codec);
1882 break;
1883 }
Kailang Yangccc656c2006-10-17 12:32:26 +02001884}
1885
1886static void alc880_uniwill_p53_hp_automute(struct hda_codec *codec)
1887{
1888 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001889 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02001890
1891 present = snd_hda_codec_read(codec, 0x14, 0,
1892 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02001893 bits = present ? HDA_AMP_MUTE : 0;
1894 snd_hda_codec_amp_stereo(codec, 0x15, HDA_INPUT, 0, HDA_AMP_MUTE, bits);
Kailang Yangccc656c2006-10-17 12:32:26 +02001895}
1896
1897static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
1898{
1899 unsigned int present;
1900
1901 present = snd_hda_codec_read(codec, 0x21, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02001902 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
1903 present &= HDA_AMP_VOLMASK;
1904 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0,
1905 HDA_AMP_VOLMASK, present);
1906 snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0,
1907 HDA_AMP_VOLMASK, present);
Kailang Yangccc656c2006-10-17 12:32:26 +02001908}
Takashi Iwai47fd8302007-08-10 17:11:07 +02001909
Kailang Yangccc656c2006-10-17 12:32:26 +02001910static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
1911 unsigned int res)
1912{
1913 /* Looks like the unsol event is incompatible with the standard
1914 * definition. 4bit tag is placed at 28 bit!
1915 */
1916 if ((res >> 28) == ALC880_HP_EVENT)
1917 alc880_uniwill_p53_hp_automute(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001918 if ((res >> 28) == ALC880_DCVOL_EVENT)
Kailang Yangccc656c2006-10-17 12:32:26 +02001919 alc880_uniwill_p53_dcvol_automute(codec);
1920}
1921
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001922/*
1923 * F1734 pin configuration:
1924 * HP = 0x14, speaker-out = 0x15, mic = 0x18
1925 */
1926static struct hda_verb alc880_pin_f1734_init_verbs[] = {
1927 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
1928 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
1929 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
1930 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
1931
1932 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1933 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1934 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1935 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1936
1937 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1938 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1939 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1940 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1941 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1942 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1943 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1944 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1945 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02001946
Takashi Iwai937b4162008-02-11 14:52:36 +01001947 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
1948 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_DCVOL_EVENT},
1949
Takashi Iwai16ded522005-06-10 19:58:24 +02001950 { }
1951};
1952
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001953/*
1954 * ASUS pin configuration:
1955 * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
1956 */
1957static struct hda_verb alc880_pin_asus_init_verbs[] = {
1958 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
1959 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
1960 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
1961 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
1962
1963 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1964 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1965 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1966 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1967 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1968 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1969 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1970 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1971
1972 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1973 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1974 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1975 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1976 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1977 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1978 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1979 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1980 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1981
1982 { }
1983};
1984
1985/* Enable GPIO mask and set output */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001986#define alc880_gpio1_init_verbs alc_gpio1_init_verbs
1987#define alc880_gpio2_init_verbs alc_gpio2_init_verbs
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001988
Kailang Yangdf694da2005-12-05 19:42:22 +01001989/* Clevo m520g init */
1990static struct hda_verb alc880_pin_clevo_init_verbs[] = {
1991 /* headphone output */
1992 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
1993 /* line-out */
1994 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1995 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1996 /* Line-in */
1997 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1998 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1999 /* CD */
2000 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2001 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2002 /* Mic1 (rear panel) */
2003 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2004 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2005 /* Mic2 (front panel) */
2006 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2007 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2008 /* headphone */
2009 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2010 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2011 /* change to EAPD mode */
2012 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2013 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2014
2015 { }
2016};
2017
2018static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02002019 /* change to EAPD mode */
2020 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2021 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2022
Kailang Yangdf694da2005-12-05 19:42:22 +01002023 /* Headphone output */
2024 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2025 /* Front output*/
2026 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2027 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
2028
2029 /* Line In pin widget for input */
2030 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2031 /* CD pin widget for input */
2032 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2033 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2034 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2035
2036 /* change to EAPD mode */
2037 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2038 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
2039
2040 { }
2041};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002042
2043/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002044 * LG m1 express dual
2045 *
2046 * Pin assignment:
2047 * Rear Line-In/Out (blue): 0x14
2048 * Build-in Mic-In: 0x15
2049 * Speaker-out: 0x17
2050 * HP-Out (green): 0x1b
2051 * Mic-In/Out (red): 0x19
2052 * SPDIF-Out: 0x1e
2053 */
2054
2055/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
2056static hda_nid_t alc880_lg_dac_nids[3] = {
2057 0x05, 0x02, 0x03
2058};
2059
2060/* seems analog CD is not working */
2061static struct hda_input_mux alc880_lg_capture_source = {
2062 .num_items = 3,
2063 .items = {
2064 { "Mic", 0x1 },
2065 { "Line", 0x5 },
2066 { "Internal Mic", 0x6 },
2067 },
2068};
2069
2070/* 2,4,6 channel modes */
2071static struct hda_verb alc880_lg_ch2_init[] = {
2072 /* set line-in and mic-in to input */
2073 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2074 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2075 { }
2076};
2077
2078static struct hda_verb alc880_lg_ch4_init[] = {
2079 /* set line-in to out and mic-in to input */
2080 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2081 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2082 { }
2083};
2084
2085static struct hda_verb alc880_lg_ch6_init[] = {
2086 /* set line-in and mic-in to output */
2087 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2088 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2089 { }
2090};
2091
2092static struct hda_channel_mode alc880_lg_ch_modes[3] = {
2093 { 2, alc880_lg_ch2_init },
2094 { 4, alc880_lg_ch4_init },
2095 { 6, alc880_lg_ch6_init },
2096};
2097
2098static struct snd_kcontrol_new alc880_lg_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002099 HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2100 HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002101 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2102 HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
2103 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
2104 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
2105 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
2106 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
2107 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2108 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
2109 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT),
2110 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT),
2111 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT),
2112 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT),
2113 {
2114 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2115 .name = "Channel Mode",
2116 .info = alc_ch_mode_info,
2117 .get = alc_ch_mode_get,
2118 .put = alc_ch_mode_put,
2119 },
2120 { } /* end */
2121};
2122
2123static struct hda_verb alc880_lg_init_verbs[] = {
2124 /* set capture source to mic-in */
2125 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2126 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2127 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2128 /* mute all amp mixer inputs */
2129 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02002130 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2131 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002132 /* line-in to input */
2133 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2134 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2135 /* built-in mic */
2136 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2137 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2138 /* speaker-out */
2139 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2140 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2141 /* mic-in to input */
2142 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
2143 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2144 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2145 /* HP-out */
2146 {0x13, AC_VERB_SET_CONNECT_SEL, 0x03},
2147 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2148 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2149 /* jack sense */
2150 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1},
2151 { }
2152};
2153
2154/* toggle speaker-output according to the hp-jack state */
2155static void alc880_lg_automute(struct hda_codec *codec)
2156{
2157 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002158 unsigned char bits;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002159
2160 present = snd_hda_codec_read(codec, 0x1b, 0,
2161 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002162 bits = present ? HDA_AMP_MUTE : 0;
2163 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
2164 HDA_AMP_MUTE, bits);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002165}
2166
2167static void alc880_lg_unsol_event(struct hda_codec *codec, unsigned int res)
2168{
2169 /* Looks like the unsol event is incompatible with the standard
2170 * definition. 4bit tag is placed at 28 bit!
2171 */
2172 if ((res >> 28) == 0x01)
2173 alc880_lg_automute(codec);
2174}
2175
2176/*
Takashi Iwaid6815182006-03-23 16:06:23 +01002177 * LG LW20
2178 *
2179 * Pin assignment:
2180 * Speaker-out: 0x14
2181 * Mic-In: 0x18
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002182 * Built-in Mic-In: 0x19
2183 * Line-In: 0x1b
2184 * HP-Out: 0x1a
Takashi Iwaid6815182006-03-23 16:06:23 +01002185 * SPDIF-Out: 0x1e
2186 */
2187
Takashi Iwaid6815182006-03-23 16:06:23 +01002188static struct hda_input_mux alc880_lg_lw_capture_source = {
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002189 .num_items = 3,
Takashi Iwaid6815182006-03-23 16:06:23 +01002190 .items = {
2191 { "Mic", 0x0 },
2192 { "Internal Mic", 0x1 },
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002193 { "Line In", 0x2 },
Takashi Iwaid6815182006-03-23 16:06:23 +01002194 },
2195};
2196
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002197#define alc880_lg_lw_modes alc880_threestack_modes
2198
Takashi Iwaid6815182006-03-23 16:06:23 +01002199static struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002200 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2201 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2202 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2203 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
2204 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2205 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2206 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2207 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2208 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2209 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaid6815182006-03-23 16:06:23 +01002210 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2211 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2212 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
2213 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002214 {
2215 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2216 .name = "Channel Mode",
2217 .info = alc_ch_mode_info,
2218 .get = alc_ch_mode_get,
2219 .put = alc_ch_mode_put,
2220 },
Takashi Iwaid6815182006-03-23 16:06:23 +01002221 { } /* end */
2222};
2223
2224static struct hda_verb alc880_lg_lw_init_verbs[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002225 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2226 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
2227 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
2228
Takashi Iwaid6815182006-03-23 16:06:23 +01002229 /* set capture source to mic-in */
2230 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2231 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2232 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02002233 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaid6815182006-03-23 16:06:23 +01002234 /* speaker-out */
2235 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2236 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2237 /* HP-out */
Takashi Iwaid6815182006-03-23 16:06:23 +01002238 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2239 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2240 /* mic-in to input */
2241 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2242 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2243 /* built-in mic */
2244 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2245 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2246 /* jack sense */
2247 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1},
2248 { }
2249};
2250
2251/* toggle speaker-output according to the hp-jack state */
2252static void alc880_lg_lw_automute(struct hda_codec *codec)
2253{
2254 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002255 unsigned char bits;
Takashi Iwaid6815182006-03-23 16:06:23 +01002256
2257 present = snd_hda_codec_read(codec, 0x1b, 0,
2258 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002259 bits = present ? HDA_AMP_MUTE : 0;
2260 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
2261 HDA_AMP_MUTE, bits);
Takashi Iwaid6815182006-03-23 16:06:23 +01002262}
2263
2264static void alc880_lg_lw_unsol_event(struct hda_codec *codec, unsigned int res)
2265{
2266 /* Looks like the unsol event is incompatible with the standard
2267 * definition. 4bit tag is placed at 28 bit!
2268 */
2269 if ((res >> 28) == 0x01)
2270 alc880_lg_lw_automute(codec);
2271}
2272
Takashi Iwaicb53c622007-08-10 17:21:45 +02002273#ifdef CONFIG_SND_HDA_POWER_SAVE
2274static struct hda_amp_list alc880_loopbacks[] = {
2275 { 0x0b, HDA_INPUT, 0 },
2276 { 0x0b, HDA_INPUT, 1 },
2277 { 0x0b, HDA_INPUT, 2 },
2278 { 0x0b, HDA_INPUT, 3 },
2279 { 0x0b, HDA_INPUT, 4 },
2280 { } /* end */
2281};
2282
2283static struct hda_amp_list alc880_lg_loopbacks[] = {
2284 { 0x0b, HDA_INPUT, 1 },
2285 { 0x0b, HDA_INPUT, 6 },
2286 { 0x0b, HDA_INPUT, 7 },
2287 { } /* end */
2288};
2289#endif
2290
Takashi Iwaid6815182006-03-23 16:06:23 +01002291/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002292 * Common callbacks
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002293 */
Takashi Iwai16ded522005-06-10 19:58:24 +02002294
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295static int alc_init(struct hda_codec *codec)
2296{
2297 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002298 unsigned int i;
2299
2300 for (i = 0; i < spec->num_init_verbs; i++)
2301 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002302
2303 if (spec->init_hook)
2304 spec->init_hook(codec);
2305
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306 return 0;
2307}
2308
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002309static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
2310{
2311 struct alc_spec *spec = codec->spec;
2312
2313 if (spec->unsol_event)
2314 spec->unsol_event(codec, res);
2315}
2316
Takashi Iwaicb53c622007-08-10 17:21:45 +02002317#ifdef CONFIG_SND_HDA_POWER_SAVE
2318static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
2319{
2320 struct alc_spec *spec = codec->spec;
2321 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
2322}
2323#endif
2324
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325/*
2326 * Analog playback callbacks
2327 */
2328static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
2329 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002330 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331{
2332 struct alc_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01002333 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
2334 hinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335}
2336
2337static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2338 struct hda_codec *codec,
2339 unsigned int stream_tag,
2340 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002341 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342{
2343 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002344 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
2345 stream_tag, format, substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346}
2347
2348static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
2349 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002350 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351{
2352 struct alc_spec *spec = codec->spec;
2353 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
2354}
2355
2356/*
2357 * Digital out
2358 */
2359static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
2360 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002361 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362{
2363 struct alc_spec *spec = codec->spec;
2364 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
2365}
2366
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002367static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2368 struct hda_codec *codec,
2369 unsigned int stream_tag,
2370 unsigned int format,
2371 struct snd_pcm_substream *substream)
2372{
2373 struct alc_spec *spec = codec->spec;
2374 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
2375 stream_tag, format, substream);
2376}
2377
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
2379 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002380 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381{
2382 struct alc_spec *spec = codec->spec;
2383 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
2384}
2385
2386/*
2387 * Analog capture
2388 */
Takashi Iwai63300792008-01-24 15:31:36 +01002389static int alc880_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390 struct hda_codec *codec,
2391 unsigned int stream_tag,
2392 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002393 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394{
2395 struct alc_spec *spec = codec->spec;
2396
Takashi Iwai63300792008-01-24 15:31:36 +01002397 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398 stream_tag, 0, format);
2399 return 0;
2400}
2401
Takashi Iwai63300792008-01-24 15:31:36 +01002402static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002404 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405{
2406 struct alc_spec *spec = codec->spec;
2407
Takashi Iwai63300792008-01-24 15:31:36 +01002408 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002409 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410 return 0;
2411}
2412
2413
2414/*
2415 */
2416static struct hda_pcm_stream alc880_pcm_analog_playback = {
2417 .substreams = 1,
2418 .channels_min = 2,
2419 .channels_max = 8,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002420 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421 .ops = {
2422 .open = alc880_playback_pcm_open,
2423 .prepare = alc880_playback_pcm_prepare,
2424 .cleanup = alc880_playback_pcm_cleanup
2425 },
2426};
2427
2428static struct hda_pcm_stream alc880_pcm_analog_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01002429 .substreams = 1,
2430 .channels_min = 2,
2431 .channels_max = 2,
2432 /* NID is set in alc_build_pcms */
2433};
2434
2435static struct hda_pcm_stream alc880_pcm_analog_alt_playback = {
2436 .substreams = 1,
2437 .channels_min = 2,
2438 .channels_max = 2,
2439 /* NID is set in alc_build_pcms */
2440};
2441
2442static struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
2443 .substreams = 2, /* can be overridden */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444 .channels_min = 2,
2445 .channels_max = 2,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002446 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447 .ops = {
Takashi Iwai63300792008-01-24 15:31:36 +01002448 .prepare = alc880_alt_capture_pcm_prepare,
2449 .cleanup = alc880_alt_capture_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450 },
2451};
2452
2453static struct hda_pcm_stream alc880_pcm_digital_playback = {
2454 .substreams = 1,
2455 .channels_min = 2,
2456 .channels_max = 2,
2457 /* NID is set in alc_build_pcms */
2458 .ops = {
2459 .open = alc880_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002460 .close = alc880_dig_playback_pcm_close,
2461 .prepare = alc880_dig_playback_pcm_prepare
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462 },
2463};
2464
2465static struct hda_pcm_stream alc880_pcm_digital_capture = {
2466 .substreams = 1,
2467 .channels_min = 2,
2468 .channels_max = 2,
2469 /* NID is set in alc_build_pcms */
2470};
2471
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01002472/* Used by alc_build_pcms to flag that a PCM has no playback stream */
Takashi Iwai63300792008-01-24 15:31:36 +01002473static struct hda_pcm_stream alc_pcm_null_stream = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01002474 .substreams = 0,
2475 .channels_min = 0,
2476 .channels_max = 0,
2477};
2478
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479static int alc_build_pcms(struct hda_codec *codec)
2480{
2481 struct alc_spec *spec = codec->spec;
2482 struct hda_pcm *info = spec->pcm_rec;
2483 int i;
2484
2485 codec->num_pcms = 1;
2486 codec->pcm_info = info;
2487
2488 info->name = spec->stream_name_analog;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002489 if (spec->stream_analog_playback) {
2490 snd_assert(spec->multiout.dac_nids, return -EINVAL);
2491 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
2492 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
2493 }
2494 if (spec->stream_analog_capture) {
2495 snd_assert(spec->adc_nids, return -EINVAL);
2496 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
2497 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
2498 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499
Takashi Iwai4a471b72005-12-07 13:56:29 +01002500 if (spec->channel_mode) {
2501 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
2502 for (i = 0; i < spec->num_channel_mode; i++) {
2503 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
2504 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
2505 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506 }
2507 }
2508
Takashi Iwaie08a0072006-09-07 17:52:14 +02002509 /* SPDIF for stream index #1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02002511 codec->num_pcms = 2;
Takashi Iwaic06134d2006-10-11 18:49:13 +02002512 info = spec->pcm_rec + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513 info->name = spec->stream_name_digital;
Takashi Iwai7ba72ba2008-02-06 14:03:20 +01002514 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002515 if (spec->multiout.dig_out_nid &&
2516 spec->stream_digital_playback) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
2518 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
2519 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01002520 if (spec->dig_in_nid &&
2521 spec->stream_digital_capture) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
2523 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
2524 }
2525 }
2526
Takashi Iwaie08a0072006-09-07 17:52:14 +02002527 /* If the use of more than one ADC is requested for the current
2528 * model, configure a second analog capture-only PCM.
2529 */
2530 /* Additional Analaog capture for index #2 */
Takashi Iwai63300792008-01-24 15:31:36 +01002531 if ((spec->alt_dac_nid && spec->stream_analog_alt_playback) ||
2532 (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture)) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02002533 codec->num_pcms = 3;
Takashi Iwaic06134d2006-10-11 18:49:13 +02002534 info = spec->pcm_rec + 2;
Takashi Iwaie08a0072006-09-07 17:52:14 +02002535 info->name = spec->stream_name_analog;
Takashi Iwai63300792008-01-24 15:31:36 +01002536 if (spec->alt_dac_nid) {
2537 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
2538 *spec->stream_analog_alt_playback;
2539 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
2540 spec->alt_dac_nid;
2541 } else {
2542 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
2543 alc_pcm_null_stream;
2544 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
2545 }
2546 if (spec->num_adc_nids > 1) {
2547 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
2548 *spec->stream_analog_alt_capture;
2549 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
2550 spec->adc_nids[1];
2551 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
2552 spec->num_adc_nids - 1;
2553 } else {
2554 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
2555 alc_pcm_null_stream;
2556 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
Takashi Iwaie08a0072006-09-07 17:52:14 +02002557 }
2558 }
2559
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 return 0;
2561}
2562
2563static void alc_free(struct hda_codec *codec)
2564{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002565 struct alc_spec *spec = codec->spec;
2566 unsigned int i;
2567
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002568 if (!spec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002569 return;
2570
2571 if (spec->kctl_alloc) {
2572 for (i = 0; i < spec->num_kctl_used; i++)
2573 kfree(spec->kctl_alloc[i].name);
2574 kfree(spec->kctl_alloc);
2575 }
2576 kfree(spec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577}
2578
2579/*
2580 */
2581static struct hda_codec_ops alc_patch_ops = {
2582 .build_controls = alc_build_controls,
2583 .build_pcms = alc_build_pcms,
2584 .init = alc_init,
2585 .free = alc_free,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002586 .unsol_event = alc_unsol_event,
Takashi Iwaicb53c622007-08-10 17:21:45 +02002587#ifdef CONFIG_SND_HDA_POWER_SAVE
2588 .check_power_status = alc_check_power_status,
2589#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590};
2591
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002592
2593/*
2594 * Test configuration for debugging
2595 *
2596 * Almost all inputs/outputs are enabled. I/O pins can be configured via
2597 * enum controls.
2598 */
2599#ifdef CONFIG_SND_DEBUG
2600static hda_nid_t alc880_test_dac_nids[4] = {
2601 0x02, 0x03, 0x04, 0x05
2602};
2603
2604static struct hda_input_mux alc880_test_capture_source = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002605 .num_items = 7,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002606 .items = {
2607 { "In-1", 0x0 },
2608 { "In-2", 0x1 },
2609 { "In-3", 0x2 },
2610 { "In-4", 0x3 },
2611 { "CD", 0x4 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002612 { "Front", 0x5 },
2613 { "Surround", 0x6 },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002614 },
2615};
2616
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002617static struct hda_channel_mode alc880_test_modes[4] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002618 { 2, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02002619 { 4, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002620 { 6, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02002621 { 8, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002622};
2623
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002624static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
2625 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002626{
2627 static char *texts[] = {
2628 "N/A", "Line Out", "HP Out",
2629 "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
2630 };
2631 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2632 uinfo->count = 1;
2633 uinfo->value.enumerated.items = 8;
2634 if (uinfo->value.enumerated.item >= 8)
2635 uinfo->value.enumerated.item = 7;
2636 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
2637 return 0;
2638}
2639
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002640static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol,
2641 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002642{
2643 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2644 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
2645 unsigned int pin_ctl, item = 0;
2646
2647 pin_ctl = snd_hda_codec_read(codec, nid, 0,
2648 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
2649 if (pin_ctl & AC_PINCTL_OUT_EN) {
2650 if (pin_ctl & AC_PINCTL_HP_EN)
2651 item = 2;
2652 else
2653 item = 1;
2654 } else if (pin_ctl & AC_PINCTL_IN_EN) {
2655 switch (pin_ctl & AC_PINCTL_VREFEN) {
2656 case AC_PINCTL_VREF_HIZ: item = 3; break;
2657 case AC_PINCTL_VREF_50: item = 4; break;
2658 case AC_PINCTL_VREF_GRD: item = 5; break;
2659 case AC_PINCTL_VREF_80: item = 6; break;
2660 case AC_PINCTL_VREF_100: item = 7; break;
2661 }
2662 }
2663 ucontrol->value.enumerated.item[0] = item;
2664 return 0;
2665}
2666
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002667static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
2668 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002669{
2670 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2671 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
2672 static unsigned int ctls[] = {
2673 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
2674 AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
2675 AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
2676 AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
2677 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
2678 AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
2679 };
2680 unsigned int old_ctl, new_ctl;
2681
2682 old_ctl = snd_hda_codec_read(codec, nid, 0,
2683 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
2684 new_ctl = ctls[ucontrol->value.enumerated.item[0]];
2685 if (old_ctl != new_ctl) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002686 int val;
2687 snd_hda_codec_write_cache(codec, nid, 0,
2688 AC_VERB_SET_PIN_WIDGET_CONTROL,
2689 new_ctl);
Takashi Iwai47fd8302007-08-10 17:11:07 +02002690 val = ucontrol->value.enumerated.item[0] >= 3 ?
2691 HDA_AMP_MUTE : 0;
2692 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
2693 HDA_AMP_MUTE, val);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002694 return 1;
2695 }
2696 return 0;
2697}
2698
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002699static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
2700 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002701{
2702 static char *texts[] = {
2703 "Front", "Surround", "CLFE", "Side"
2704 };
2705 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2706 uinfo->count = 1;
2707 uinfo->value.enumerated.items = 4;
2708 if (uinfo->value.enumerated.item >= 4)
2709 uinfo->value.enumerated.item = 3;
2710 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
2711 return 0;
2712}
2713
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002714static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol,
2715 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002716{
2717 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2718 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
2719 unsigned int sel;
2720
2721 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
2722 ucontrol->value.enumerated.item[0] = sel & 3;
2723 return 0;
2724}
2725
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002726static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
2727 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002728{
2729 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2730 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
2731 unsigned int sel;
2732
2733 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
2734 if (ucontrol->value.enumerated.item[0] != sel) {
2735 sel = ucontrol->value.enumerated.item[0] & 3;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002736 snd_hda_codec_write_cache(codec, nid, 0,
2737 AC_VERB_SET_CONNECT_SEL, sel);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002738 return 1;
2739 }
2740 return 0;
2741}
2742
2743#define PIN_CTL_TEST(xname,nid) { \
2744 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2745 .name = xname, \
2746 .info = alc_test_pin_ctl_info, \
2747 .get = alc_test_pin_ctl_get, \
2748 .put = alc_test_pin_ctl_put, \
2749 .private_value = nid \
2750 }
2751
2752#define PIN_SRC_TEST(xname,nid) { \
2753 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2754 .name = xname, \
2755 .info = alc_test_pin_src_info, \
2756 .get = alc_test_pin_src_get, \
2757 .put = alc_test_pin_src_put, \
2758 .private_value = nid \
2759 }
2760
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002761static struct snd_kcontrol_new alc880_test_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02002762 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2763 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2764 HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
2765 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002766 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2767 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
2768 HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
2769 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002770 PIN_CTL_TEST("Front Pin Mode", 0x14),
2771 PIN_CTL_TEST("Surround Pin Mode", 0x15),
2772 PIN_CTL_TEST("CLFE Pin Mode", 0x16),
2773 PIN_CTL_TEST("Side Pin Mode", 0x17),
2774 PIN_CTL_TEST("In-1 Pin Mode", 0x18),
2775 PIN_CTL_TEST("In-2 Pin Mode", 0x19),
2776 PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
2777 PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
2778 PIN_SRC_TEST("In-1 Pin Source", 0x18),
2779 PIN_SRC_TEST("In-2 Pin Source", 0x19),
2780 PIN_SRC_TEST("In-3 Pin Source", 0x1a),
2781 PIN_SRC_TEST("In-4 Pin Source", 0x1b),
2782 HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
2783 HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
2784 HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
2785 HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
2786 HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
2787 HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
2788 HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
2789 HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
2790 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
2791 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002792 {
2793 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2794 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002795 .info = alc_ch_mode_info,
2796 .get = alc_ch_mode_get,
2797 .put = alc_ch_mode_put,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002798 },
2799 { } /* end */
2800};
2801
2802static struct hda_verb alc880_test_init_verbs[] = {
2803 /* Unmute inputs of 0x0c - 0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02002804 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2805 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2806 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2807 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2808 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2809 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2810 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2811 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002812 /* Vol output for 0x0c-0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02002813 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2814 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2815 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2816 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002817 /* Set output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02002818 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2819 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2820 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2821 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002822 /* Unmute output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02002823 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2824 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2825 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2826 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002827 /* Set input pins 0x18-0x1c */
Takashi Iwai16ded522005-06-10 19:58:24 +02002828 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2829 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai05acb862005-06-10 19:50:25 +02002830 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2831 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2832 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002833 /* Mute input pins 0x18-0x1b */
Takashi Iwai05acb862005-06-10 19:50:25 +02002834 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2835 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2836 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2837 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002838 /* ADC set up */
Takashi Iwai05acb862005-06-10 19:50:25 +02002839 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002840 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02002841 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002842 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02002843 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002844 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02002845 /* Analog input/passthru */
2846 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2847 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2848 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2849 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2850 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002851 { }
2852};
2853#endif
2854
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855/*
2856 */
2857
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002858static const char *alc880_models[ALC880_MODEL_LAST] = {
2859 [ALC880_3ST] = "3stack",
2860 [ALC880_TCL_S700] = "tcl",
2861 [ALC880_3ST_DIG] = "3stack-digout",
2862 [ALC880_CLEVO] = "clevo",
2863 [ALC880_5ST] = "5stack",
2864 [ALC880_5ST_DIG] = "5stack-digout",
2865 [ALC880_W810] = "w810",
2866 [ALC880_Z71V] = "z71v",
2867 [ALC880_6ST] = "6stack",
2868 [ALC880_6ST_DIG] = "6stack-digout",
2869 [ALC880_ASUS] = "asus",
2870 [ALC880_ASUS_W1V] = "asus-w1v",
2871 [ALC880_ASUS_DIG] = "asus-dig",
2872 [ALC880_ASUS_DIG2] = "asus-dig2",
2873 [ALC880_UNIWILL_DIG] = "uniwill",
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01002874 [ALC880_UNIWILL_P53] = "uniwill-p53",
2875 [ALC880_FUJITSU] = "fujitsu",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002876 [ALC880_F1734] = "F1734",
2877 [ALC880_LG] = "lg",
2878 [ALC880_LG_LW] = "lg-lw",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002879#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002880 [ALC880_TEST] = "test",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002881#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002882 [ALC880_AUTO] = "auto",
2883};
2884
2885static struct snd_pci_quirk alc880_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002886 SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002887 SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
2888 SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
2889 SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
2890 SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
2891 SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
2892 SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
2893 SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
2894 SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002895 SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
2896 SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002897 SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
2898 SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
2899 SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
2900 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
2901 SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
2902 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
2903 SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
2904 /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
2905 SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
2906 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
Tobin Davis0e4ceb72007-01-08 10:54:26 +01002907 SND_PCI_QUIRK(0x1043, 0x814e, "ASUS", ALC880_ASUS),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002908 SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
2909 SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
2910 SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002911 SND_PCI_QUIRK(0x1043, 0, "ASUS", ALC880_ASUS), /* default ASUS */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002912 SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002913 SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
2914 SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002915 SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
2916 SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002917 SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
2918 SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
2919 SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
2920 SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002921 SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
2922 SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002923 SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002924 SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002925 SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002926 SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002927 SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
2928 SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002929 SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
2930 SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002931 SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002932 SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002933 SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01002934 SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002935 SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002936 SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
2937 SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002938 SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002939 SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
2940 SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
2941 SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
2942 SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002943 SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
2944 SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002945 SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002946 SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002947 SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
2948 SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002949 SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
2950 SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
2951 SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002952 SND_PCI_QUIRK(0x8086, 0, "Intel mobo", ALC880_3ST), /* default Intel */
2953 SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
2954 SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 {}
2956};
2957
Takashi Iwai16ded522005-06-10 19:58:24 +02002958/*
Kailang Yangdf694da2005-12-05 19:42:22 +01002959 * ALC880 codec presets
Takashi Iwai16ded522005-06-10 19:58:24 +02002960 */
Takashi Iwai16ded522005-06-10 19:58:24 +02002961static struct alc_config_preset alc880_presets[] = {
2962 [ALC880_3ST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002963 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002964 .init_verbs = { alc880_volume_init_verbs,
2965 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02002966 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02002967 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02002968 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
2969 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02002970 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02002971 .input_mux = &alc880_capture_source,
2972 },
2973 [ALC880_3ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002974 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002975 .init_verbs = { alc880_volume_init_verbs,
2976 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02002977 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02002978 .dac_nids = alc880_dac_nids,
2979 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02002980 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
2981 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02002982 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02002983 .input_mux = &alc880_capture_source,
2984 },
Kailang Yangdf694da2005-12-05 19:42:22 +01002985 [ALC880_TCL_S700] = {
2986 .mixers = { alc880_tcl_s700_mixer },
2987 .init_verbs = { alc880_volume_init_verbs,
2988 alc880_pin_tcl_S700_init_verbs,
2989 alc880_gpio2_init_verbs },
2990 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
2991 .dac_nids = alc880_dac_nids,
2992 .hp_nid = 0x03,
2993 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
2994 .channel_mode = alc880_2_jack_modes,
2995 .input_mux = &alc880_capture_source,
2996 },
Takashi Iwai16ded522005-06-10 19:58:24 +02002997 [ALC880_5ST] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002998 .mixers = { alc880_three_stack_mixer,
2999 alc880_five_stack_mixer},
3000 .init_verbs = { alc880_volume_init_verbs,
3001 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003002 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3003 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003004 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
3005 .channel_mode = alc880_fivestack_modes,
3006 .input_mux = &alc880_capture_source,
3007 },
3008 [ALC880_5ST_DIG] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003009 .mixers = { alc880_three_stack_mixer,
3010 alc880_five_stack_mixer },
3011 .init_verbs = { alc880_volume_init_verbs,
3012 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003013 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3014 .dac_nids = alc880_dac_nids,
3015 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003016 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
3017 .channel_mode = alc880_fivestack_modes,
3018 .input_mux = &alc880_capture_source,
3019 },
Takashi Iwaib6482d42005-06-27 15:32:43 +02003020 [ALC880_6ST] = {
3021 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003022 .init_verbs = { alc880_volume_init_verbs,
3023 alc880_pin_6stack_init_verbs },
Takashi Iwaib6482d42005-06-27 15:32:43 +02003024 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
3025 .dac_nids = alc880_6st_dac_nids,
3026 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
3027 .channel_mode = alc880_sixstack_modes,
3028 .input_mux = &alc880_6stack_capture_source,
3029 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003030 [ALC880_6ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003031 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003032 .init_verbs = { alc880_volume_init_verbs,
3033 alc880_pin_6stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003034 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
3035 .dac_nids = alc880_6st_dac_nids,
3036 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003037 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
3038 .channel_mode = alc880_sixstack_modes,
3039 .input_mux = &alc880_6stack_capture_source,
3040 },
3041 [ALC880_W810] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003042 .mixers = { alc880_w810_base_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003043 .init_verbs = { alc880_volume_init_verbs,
3044 alc880_pin_w810_init_verbs,
Takashi Iwaib0af0de2005-06-21 14:49:19 +02003045 alc880_gpio2_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003046 .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
3047 .dac_nids = alc880_w810_dac_nids,
3048 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003049 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
3050 .channel_mode = alc880_w810_modes,
3051 .input_mux = &alc880_capture_source,
3052 },
3053 [ALC880_Z71V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003054 .mixers = { alc880_z71v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003055 .init_verbs = { alc880_volume_init_verbs,
3056 alc880_pin_z71v_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003057 .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
3058 .dac_nids = alc880_z71v_dac_nids,
3059 .dig_out_nid = ALC880_DIGOUT_NID,
3060 .hp_nid = 0x03,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003061 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3062 .channel_mode = alc880_2_jack_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02003063 .input_mux = &alc880_capture_source,
3064 },
3065 [ALC880_F1734] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003066 .mixers = { alc880_f1734_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003067 .init_verbs = { alc880_volume_init_verbs,
3068 alc880_pin_f1734_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003069 .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
3070 .dac_nids = alc880_f1734_dac_nids,
3071 .hp_nid = 0x02,
3072 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3073 .channel_mode = alc880_2_jack_modes,
Takashi Iwai937b4162008-02-11 14:52:36 +01003074 .input_mux = &alc880_f1734_capture_source,
3075 .unsol_event = alc880_uniwill_p53_unsol_event,
3076 .init_hook = alc880_uniwill_p53_hp_automute,
Takashi Iwai16ded522005-06-10 19:58:24 +02003077 },
3078 [ALC880_ASUS] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003079 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003080 .init_verbs = { alc880_volume_init_verbs,
3081 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003082 alc880_gpio1_init_verbs },
3083 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3084 .dac_nids = alc880_asus_dac_nids,
3085 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3086 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003087 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003088 .input_mux = &alc880_capture_source,
3089 },
3090 [ALC880_ASUS_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003091 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003092 .init_verbs = { alc880_volume_init_verbs,
3093 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003094 alc880_gpio1_init_verbs },
3095 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3096 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003097 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003098 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3099 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003100 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003101 .input_mux = &alc880_capture_source,
3102 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003103 [ALC880_ASUS_DIG2] = {
3104 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003105 .init_verbs = { alc880_volume_init_verbs,
3106 alc880_pin_asus_init_verbs,
Kailang Yangdf694da2005-12-05 19:42:22 +01003107 alc880_gpio2_init_verbs }, /* use GPIO2 */
3108 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3109 .dac_nids = alc880_asus_dac_nids,
3110 .dig_out_nid = ALC880_DIGOUT_NID,
3111 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3112 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003113 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01003114 .input_mux = &alc880_capture_source,
3115 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003116 [ALC880_ASUS_W1V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003117 .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003118 .init_verbs = { alc880_volume_init_verbs,
3119 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003120 alc880_gpio1_init_verbs },
3121 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3122 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003123 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003124 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3125 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003126 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003127 .input_mux = &alc880_capture_source,
3128 },
3129 [ALC880_UNIWILL_DIG] = {
Takashi Iwai3c10a9d2005-08-23 20:02:27 +02003130 .mixers = { alc880_asus_mixer, alc880_pcbeep_mixer },
Kailang Yangccc656c2006-10-17 12:32:26 +02003131 .init_verbs = { alc880_volume_init_verbs,
3132 alc880_pin_asus_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003133 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3134 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003135 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003136 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3137 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003138 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003139 .input_mux = &alc880_capture_source,
3140 },
Kailang Yangccc656c2006-10-17 12:32:26 +02003141 [ALC880_UNIWILL] = {
3142 .mixers = { alc880_uniwill_mixer },
3143 .init_verbs = { alc880_volume_init_verbs,
3144 alc880_uniwill_init_verbs },
3145 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3146 .dac_nids = alc880_asus_dac_nids,
3147 .dig_out_nid = ALC880_DIGOUT_NID,
3148 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3149 .channel_mode = alc880_threestack_modes,
3150 .need_dac_fix = 1,
3151 .input_mux = &alc880_capture_source,
3152 .unsol_event = alc880_uniwill_unsol_event,
3153 .init_hook = alc880_uniwill_automute,
3154 },
3155 [ALC880_UNIWILL_P53] = {
3156 .mixers = { alc880_uniwill_p53_mixer },
3157 .init_verbs = { alc880_volume_init_verbs,
3158 alc880_uniwill_p53_init_verbs },
3159 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3160 .dac_nids = alc880_asus_dac_nids,
3161 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003162 .channel_mode = alc880_threestack_modes,
3163 .input_mux = &alc880_capture_source,
3164 .unsol_event = alc880_uniwill_p53_unsol_event,
3165 .init_hook = alc880_uniwill_p53_hp_automute,
3166 },
3167 [ALC880_FUJITSU] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003168 .mixers = { alc880_fujitsu_mixer,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003169 alc880_pcbeep_mixer, },
3170 .init_verbs = { alc880_volume_init_verbs,
3171 alc880_uniwill_p53_init_verbs,
3172 alc880_beep_init_verbs },
3173 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3174 .dac_nids = alc880_dac_nids,
Takashi Iwaid53d7d92007-08-20 15:20:02 +02003175 .dig_out_nid = ALC880_DIGOUT_NID,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003176 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3177 .channel_mode = alc880_2_jack_modes,
Kailang Yangccc656c2006-10-17 12:32:26 +02003178 .input_mux = &alc880_capture_source,
3179 .unsol_event = alc880_uniwill_p53_unsol_event,
3180 .init_hook = alc880_uniwill_p53_hp_automute,
3181 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003182 [ALC880_CLEVO] = {
3183 .mixers = { alc880_three_stack_mixer },
3184 .init_verbs = { alc880_volume_init_verbs,
3185 alc880_pin_clevo_init_verbs },
3186 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3187 .dac_nids = alc880_dac_nids,
3188 .hp_nid = 0x03,
3189 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3190 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003191 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01003192 .input_mux = &alc880_capture_source,
3193 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003194 [ALC880_LG] = {
3195 .mixers = { alc880_lg_mixer },
3196 .init_verbs = { alc880_volume_init_verbs,
3197 alc880_lg_init_verbs },
3198 .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids),
3199 .dac_nids = alc880_lg_dac_nids,
3200 .dig_out_nid = ALC880_DIGOUT_NID,
3201 .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
3202 .channel_mode = alc880_lg_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003203 .need_dac_fix = 1,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003204 .input_mux = &alc880_lg_capture_source,
3205 .unsol_event = alc880_lg_unsol_event,
3206 .init_hook = alc880_lg_automute,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003207#ifdef CONFIG_SND_HDA_POWER_SAVE
3208 .loopbacks = alc880_lg_loopbacks,
3209#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003210 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003211 [ALC880_LG_LW] = {
3212 .mixers = { alc880_lg_lw_mixer },
3213 .init_verbs = { alc880_volume_init_verbs,
3214 alc880_lg_lw_init_verbs },
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003215 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwaid6815182006-03-23 16:06:23 +01003216 .dac_nids = alc880_dac_nids,
3217 .dig_out_nid = ALC880_DIGOUT_NID,
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003218 .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
3219 .channel_mode = alc880_lg_lw_modes,
Takashi Iwaid6815182006-03-23 16:06:23 +01003220 .input_mux = &alc880_lg_lw_capture_source,
3221 .unsol_event = alc880_lg_lw_unsol_event,
3222 .init_hook = alc880_lg_lw_automute,
3223 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003224#ifdef CONFIG_SND_DEBUG
3225 [ALC880_TEST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003226 .mixers = { alc880_test_mixer },
3227 .init_verbs = { alc880_test_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003228 .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
3229 .dac_nids = alc880_test_dac_nids,
3230 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003231 .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
3232 .channel_mode = alc880_test_modes,
3233 .input_mux = &alc880_test_capture_source,
3234 },
3235#endif
3236};
3237
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003238/*
3239 * Automatic parse of I/O pins from the BIOS configuration
3240 */
3241
3242#define NUM_CONTROL_ALLOC 32
3243#define NUM_VERB_ALLOC 32
3244
3245enum {
3246 ALC_CTL_WIDGET_VOL,
3247 ALC_CTL_WIDGET_MUTE,
3248 ALC_CTL_BIND_MUTE,
3249};
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003250static struct snd_kcontrol_new alc880_control_templates[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003251 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
3252 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Takashi Iwai985be542005-11-02 18:26:49 +01003253 HDA_BIND_MUTE(NULL, 0, 0, 0),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003254};
3255
3256/* add dynamic controls */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003257static int add_control(struct alc_spec *spec, int type, const char *name,
3258 unsigned long val)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003259{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003260 struct snd_kcontrol_new *knew;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003261
3262 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
3263 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
3264
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003265 /* array + terminator */
3266 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL);
3267 if (!knew)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003268 return -ENOMEM;
3269 if (spec->kctl_alloc) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003270 memcpy(knew, spec->kctl_alloc,
3271 sizeof(*knew) * spec->num_kctl_alloc);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003272 kfree(spec->kctl_alloc);
3273 }
3274 spec->kctl_alloc = knew;
3275 spec->num_kctl_alloc = num;
3276 }
3277
3278 knew = &spec->kctl_alloc[spec->num_kctl_used];
3279 *knew = alc880_control_templates[type];
Paulo Marques543537b2005-06-23 00:09:02 -07003280 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003281 if (!knew->name)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003282 return -ENOMEM;
3283 knew->private_value = val;
3284 spec->num_kctl_used++;
3285 return 0;
3286}
3287
3288#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
3289#define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
3290#define alc880_is_multi_pin(nid) ((nid) >= 0x18)
3291#define alc880_multi_pin_idx(nid) ((nid) - 0x18)
3292#define alc880_is_input_pin(nid) ((nid) >= 0x18)
3293#define alc880_input_pin_idx(nid) ((nid) - 0x18)
3294#define alc880_idx_to_dac(nid) ((nid) + 0x02)
3295#define alc880_dac_to_idx(nid) ((nid) - 0x02)
3296#define alc880_idx_to_mixer(nid) ((nid) + 0x0c)
3297#define alc880_idx_to_selector(nid) ((nid) + 0x10)
3298#define ALC880_PIN_CD_NID 0x1c
3299
3300/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003301static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
3302 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003303{
3304 hda_nid_t nid;
3305 int assigned[4];
3306 int i, j;
3307
3308 memset(assigned, 0, sizeof(assigned));
Takashi Iwaib0af0de2005-06-21 14:49:19 +02003309 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003310
3311 /* check the pins hardwired to audio widget */
3312 for (i = 0; i < cfg->line_outs; i++) {
3313 nid = cfg->line_out_pins[i];
3314 if (alc880_is_fixed_pin(nid)) {
3315 int idx = alc880_fixed_pin_idx(nid);
Libin Yang5014f192005-11-23 15:48:36 +01003316 spec->multiout.dac_nids[i] = alc880_idx_to_dac(idx);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003317 assigned[idx] = 1;
3318 }
3319 }
3320 /* left pins can be connect to any audio widget */
3321 for (i = 0; i < cfg->line_outs; i++) {
3322 nid = cfg->line_out_pins[i];
3323 if (alc880_is_fixed_pin(nid))
3324 continue;
3325 /* search for an empty channel */
3326 for (j = 0; j < cfg->line_outs; j++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003327 if (!assigned[j]) {
3328 spec->multiout.dac_nids[i] =
3329 alc880_idx_to_dac(j);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003330 assigned[j] = 1;
3331 break;
3332 }
3333 }
3334 }
3335 spec->multiout.num_dacs = cfg->line_outs;
3336 return 0;
3337}
3338
3339/* add playback controls from the parsed DAC table */
Kailang Yangdf694da2005-12-05 19:42:22 +01003340static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
3341 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003342{
3343 char name[32];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003344 static const char *chname[4] = {
3345 "Front", "Surround", NULL /*CLFE*/, "Side"
3346 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003347 hda_nid_t nid;
3348 int i, err;
3349
3350 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003351 if (!spec->multiout.dac_nids[i])
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003352 continue;
3353 nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
3354 if (i == 2) {
3355 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003356 err = add_control(spec, ALC_CTL_WIDGET_VOL,
3357 "Center Playback Volume",
3358 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
3359 HDA_OUTPUT));
3360 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003361 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003362 err = add_control(spec, ALC_CTL_WIDGET_VOL,
3363 "LFE Playback Volume",
3364 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
3365 HDA_OUTPUT));
3366 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003367 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003368 err = add_control(spec, ALC_CTL_BIND_MUTE,
3369 "Center Playback Switch",
3370 HDA_COMPOSE_AMP_VAL(nid, 1, 2,
3371 HDA_INPUT));
3372 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003373 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003374 err = add_control(spec, ALC_CTL_BIND_MUTE,
3375 "LFE Playback Switch",
3376 HDA_COMPOSE_AMP_VAL(nid, 2, 2,
3377 HDA_INPUT));
3378 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003379 return err;
3380 } else {
3381 sprintf(name, "%s Playback Volume", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003382 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
3383 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
3384 HDA_OUTPUT));
3385 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003386 return err;
3387 sprintf(name, "%s Playback Switch", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003388 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
3389 HDA_COMPOSE_AMP_VAL(nid, 3, 2,
3390 HDA_INPUT));
3391 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003392 return err;
3393 }
3394 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003395 return 0;
3396}
3397
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003398/* add playback controls for speaker and HP outputs */
3399static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
3400 const char *pfx)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003401{
3402 hda_nid_t nid;
3403 int err;
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003404 char name[32];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003405
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003406 if (!pin)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003407 return 0;
3408
3409 if (alc880_is_fixed_pin(pin)) {
3410 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
Takashi Iwai82bc9552006-03-21 11:24:42 +01003411 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003412 if (!spec->multiout.hp_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003413 spec->multiout.hp_nid = nid;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003414 else
3415 spec->multiout.extra_out_nid[0] = nid;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003416 /* control HP volume/switch on the output mixer amp */
3417 nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003418 sprintf(name, "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003419 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
3420 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
3421 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003422 return err;
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003423 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003424 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
3425 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
3426 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003427 return err;
3428 } else if (alc880_is_multi_pin(pin)) {
3429 /* set manual connection */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003430 /* we have only a switch on HP-out PIN */
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003431 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003432 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
3433 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
3434 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003435 return err;
3436 }
3437 return 0;
3438}
3439
3440/* create input playback/capture controls for the given pin */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003441static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
3442 const char *ctlname,
Kailang Yangdf694da2005-12-05 19:42:22 +01003443 int idx, hda_nid_t mix_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003444{
3445 char name[32];
Kailang Yangdf694da2005-12-05 19:42:22 +01003446 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003447
3448 sprintf(name, "%s Playback Volume", ctlname);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003449 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
3450 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
3451 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003452 return err;
3453 sprintf(name, "%s Playback Switch", ctlname);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003454 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
3455 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
3456 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003457 return err;
3458 return 0;
3459}
3460
3461/* create playback/capture controls for input pins */
Kailang Yangdf694da2005-12-05 19:42:22 +01003462static int alc880_auto_create_analog_input_ctls(struct alc_spec *spec,
3463 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003464{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003465 struct hda_input_mux *imux = &spec->private_imux;
Kailang Yangdf694da2005-12-05 19:42:22 +01003466 int i, err, idx;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003467
3468 for (i = 0; i < AUTO_PIN_LAST; i++) {
3469 if (alc880_is_input_pin(cfg->input_pins[i])) {
Kailang Yangdf694da2005-12-05 19:42:22 +01003470 idx = alc880_input_pin_idx(cfg->input_pins[i]);
Takashi Iwai4a471b72005-12-07 13:56:29 +01003471 err = new_analog_input(spec, cfg->input_pins[i],
3472 auto_pin_cfg_labels[i],
Kailang Yangdf694da2005-12-05 19:42:22 +01003473 idx, 0x0b);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003474 if (err < 0)
3475 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003476 imux->items[imux->num_items].label =
3477 auto_pin_cfg_labels[i];
3478 imux->items[imux->num_items].index =
3479 alc880_input_pin_idx(cfg->input_pins[i]);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003480 imux->num_items++;
3481 }
3482 }
3483 return 0;
3484}
3485
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003486static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
3487 unsigned int pin_type)
3488{
3489 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
3490 pin_type);
3491 /* unmute pin */
Takashi Iwaid260cdf2008-02-13 17:19:35 +01003492 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
3493 AMP_OUT_UNMUTE);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003494}
3495
Kailang Yangdf694da2005-12-05 19:42:22 +01003496static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
3497 hda_nid_t nid, int pin_type,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003498 int dac_idx)
3499{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003500 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003501 /* need the manual connection? */
3502 if (alc880_is_multi_pin(nid)) {
3503 struct alc_spec *spec = codec->spec;
3504 int idx = alc880_multi_pin_idx(nid);
3505 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
3506 AC_VERB_SET_CONNECT_SEL,
3507 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
3508 }
3509}
3510
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02003511static int get_pin_type(int line_out_type)
3512{
3513 if (line_out_type == AUTO_PIN_HP_OUT)
3514 return PIN_HP;
3515 else
3516 return PIN_OUT;
3517}
3518
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003519static void alc880_auto_init_multi_out(struct hda_codec *codec)
3520{
3521 struct alc_spec *spec = codec->spec;
3522 int i;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003523
3524 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003525 for (i = 0; i < spec->autocfg.line_outs; i++) {
3526 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02003527 int pin_type = get_pin_type(spec->autocfg.line_out_type);
3528 alc880_auto_set_output_and_unmute(codec, nid, pin_type, i);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003529 }
3530}
3531
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003532static void alc880_auto_init_extra_out(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003533{
3534 struct alc_spec *spec = codec->spec;
3535 hda_nid_t pin;
3536
Takashi Iwai82bc9552006-03-21 11:24:42 +01003537 pin = spec->autocfg.speaker_pins[0];
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003538 if (pin) /* connect to front */
3539 alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003540 pin = spec->autocfg.hp_pins[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003541 if (pin) /* connect to front */
3542 alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
3543}
3544
3545static void alc880_auto_init_analog_input(struct hda_codec *codec)
3546{
3547 struct alc_spec *spec = codec->spec;
3548 int i;
3549
3550 for (i = 0; i < AUTO_PIN_LAST; i++) {
3551 hda_nid_t nid = spec->autocfg.input_pins[i];
3552 if (alc880_is_input_pin(nid)) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003553 snd_hda_codec_write(codec, nid, 0,
3554 AC_VERB_SET_PIN_WIDGET_CONTROL,
3555 i <= AUTO_PIN_FRONT_MIC ?
3556 PIN_VREF80 : PIN_IN);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003557 if (nid != ALC880_PIN_CD_NID)
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003558 snd_hda_codec_write(codec, nid, 0,
3559 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003560 AMP_OUT_MUTE);
3561 }
3562 }
3563}
3564
3565/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003566/* return 1 if successful, 0 if the proper config is not found,
3567 * or a negative error code
3568 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003569static int alc880_parse_auto_config(struct hda_codec *codec)
3570{
3571 struct alc_spec *spec = codec->spec;
3572 int err;
Kailang Yangdf694da2005-12-05 19:42:22 +01003573 static hda_nid_t alc880_ignore[] = { 0x1d, 0 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003574
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003575 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
3576 alc880_ignore);
3577 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003578 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003579 if (!spec->autocfg.line_outs)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003580 return 0; /* can't find valid BIOS pin config */
Kailang Yangdf694da2005-12-05 19:42:22 +01003581
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003582 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
3583 if (err < 0)
3584 return err;
3585 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
3586 if (err < 0)
3587 return err;
3588 err = alc880_auto_create_extra_out(spec,
3589 spec->autocfg.speaker_pins[0],
3590 "Speaker");
3591 if (err < 0)
3592 return err;
3593 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
3594 "Headphone");
3595 if (err < 0)
3596 return err;
3597 err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg);
3598 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003599 return err;
3600
3601 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
3602
3603 if (spec->autocfg.dig_out_pin)
3604 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
3605 if (spec->autocfg.dig_in_pin)
3606 spec->dig_in_nid = ALC880_DIGIN_NID;
3607
3608 if (spec->kctl_alloc)
3609 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
3610
3611 spec->init_verbs[spec->num_init_verbs++] = alc880_volume_init_verbs;
3612
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003613 spec->num_mux_defs = 1;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003614 spec->input_mux = &spec->private_imux;
3615
3616 return 1;
3617}
3618
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003619/* additional initialization for auto-configuration model */
3620static void alc880_auto_init(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003621{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003622 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003623 alc880_auto_init_multi_out(codec);
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003624 alc880_auto_init_extra_out(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003625 alc880_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003626 if (spec->unsol_event)
3627 alc_sku_automute(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003628}
3629
3630/*
3631 * OK, here we have finally the patch for ALC880
3632 */
3633
Linus Torvalds1da177e2005-04-16 15:20:36 -07003634static int patch_alc880(struct hda_codec *codec)
3635{
3636 struct alc_spec *spec;
3637 int board_config;
Kailang Yangdf694da2005-12-05 19:42:22 +01003638 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003639
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003640 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003641 if (spec == NULL)
3642 return -ENOMEM;
3643
3644 codec->spec = spec;
3645
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003646 board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
3647 alc880_models,
3648 alc880_cfg_tbl);
3649 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003650 printk(KERN_INFO "hda_codec: Unknown model for ALC880, "
3651 "trying auto-probe from BIOS...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003652 board_config = ALC880_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003653 }
3654
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003655 if (board_config == ALC880_AUTO) {
3656 /* automatic parse from the BIOS config */
3657 err = alc880_parse_auto_config(codec);
3658 if (err < 0) {
3659 alc_free(codec);
3660 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003661 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003662 printk(KERN_INFO
3663 "hda_codec: Cannot set up configuration "
3664 "from BIOS. Using 3-stack mode...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003665 board_config = ALC880_3ST;
3666 }
3667 }
3668
Kailang Yangdf694da2005-12-05 19:42:22 +01003669 if (board_config != ALC880_AUTO)
3670 setup_preset(spec, &alc880_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003671
3672 spec->stream_name_analog = "ALC880 Analog";
3673 spec->stream_analog_playback = &alc880_pcm_analog_playback;
3674 spec->stream_analog_capture = &alc880_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01003675 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676
3677 spec->stream_name_digital = "ALC880 Digital";
3678 spec->stream_digital_playback = &alc880_pcm_digital_playback;
3679 spec->stream_digital_capture = &alc880_pcm_digital_capture;
3680
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003681 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003682 /* check whether NID 0x07 is valid */
Takashi Iwai54d17402005-11-21 16:33:22 +01003683 unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003684 /* get type */
3685 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003686 if (wcap != AC_WID_AUD_IN) {
3687 spec->adc_nids = alc880_adc_nids_alt;
3688 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003689 spec->mixers[spec->num_mixers] =
3690 alc880_capture_alt_mixer;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003691 spec->num_mixers++;
3692 } else {
3693 spec->adc_nids = alc880_adc_nids;
3694 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
3695 spec->mixers[spec->num_mixers] = alc880_capture_mixer;
3696 spec->num_mixers++;
3697 }
3698 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003699
Takashi Iwai2134ea42008-01-10 16:53:55 +01003700 spec->vmaster_nid = 0x0c;
3701
Linus Torvalds1da177e2005-04-16 15:20:36 -07003702 codec->patch_ops = alc_patch_ops;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003703 if (board_config == ALC880_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003704 spec->init_hook = alc880_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02003705#ifdef CONFIG_SND_HDA_POWER_SAVE
3706 if (!spec->loopback.amplist)
3707 spec->loopback.amplist = alc880_loopbacks;
3708#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709
3710 return 0;
3711}
3712
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003713
Linus Torvalds1da177e2005-04-16 15:20:36 -07003714/*
3715 * ALC260 support
3716 */
3717
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003718static hda_nid_t alc260_dac_nids[1] = {
3719 /* front */
3720 0x02,
3721};
3722
3723static hda_nid_t alc260_adc_nids[1] = {
3724 /* ADC0 */
3725 0x04,
3726};
3727
Kailang Yangdf694da2005-12-05 19:42:22 +01003728static hda_nid_t alc260_adc_nids_alt[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003729 /* ADC1 */
3730 0x05,
3731};
3732
Kailang Yangdf694da2005-12-05 19:42:22 +01003733static hda_nid_t alc260_hp_adc_nids[2] = {
3734 /* ADC1, 0 */
3735 0x05, 0x04
3736};
3737
Jonathan Woithed57fdac2006-02-28 11:38:35 +01003738/* NIDs used when simultaneous access to both ADCs makes sense. Note that
3739 * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
3740 */
3741static hda_nid_t alc260_dual_adc_nids[2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003742 /* ADC0, ADC1 */
3743 0x04, 0x05
3744};
3745
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003746#define ALC260_DIGOUT_NID 0x03
3747#define ALC260_DIGIN_NID 0x06
3748
3749static struct hda_input_mux alc260_capture_source = {
3750 .num_items = 4,
3751 .items = {
3752 { "Mic", 0x0 },
3753 { "Front Mic", 0x1 },
3754 { "Line", 0x2 },
3755 { "CD", 0x4 },
3756 },
3757};
3758
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01003759/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003760 * headphone jack and the internal CD lines since these are the only pins at
3761 * which audio can appear. For flexibility, also allow the option of
3762 * recording the mixer output on the second ADC (ADC0 doesn't have a
3763 * connection to the mixer output).
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003764 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003765static struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
3766 {
3767 .num_items = 3,
3768 .items = {
3769 { "Mic/Line", 0x0 },
3770 { "CD", 0x4 },
3771 { "Headphone", 0x2 },
3772 },
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003773 },
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003774 {
3775 .num_items = 4,
3776 .items = {
3777 { "Mic/Line", 0x0 },
3778 { "CD", 0x4 },
3779 { "Headphone", 0x2 },
3780 { "Mixer", 0x5 },
3781 },
3782 },
3783
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003784};
3785
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003786/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
3787 * the Fujitsu S702x, but jacks are marked differently.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01003788 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003789static struct hda_input_mux alc260_acer_capture_sources[2] = {
3790 {
3791 .num_items = 4,
3792 .items = {
3793 { "Mic", 0x0 },
3794 { "Line", 0x2 },
3795 { "CD", 0x4 },
3796 { "Headphone", 0x5 },
3797 },
3798 },
3799 {
3800 .num_items = 5,
3801 .items = {
3802 { "Mic", 0x0 },
3803 { "Line", 0x2 },
3804 { "CD", 0x4 },
3805 { "Headphone", 0x6 },
3806 { "Mixer", 0x5 },
3807 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01003808 },
3809};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003810/*
3811 * This is just place-holder, so there's something for alc_build_pcms to look
3812 * at when it calculates the maximum number of channels. ALC260 has no mixer
3813 * element which allows changing the channel mode, so the verb list is
3814 * never used.
3815 */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01003816static struct hda_channel_mode alc260_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003817 { 2, NULL },
3818};
3819
Kailang Yangdf694da2005-12-05 19:42:22 +01003820
3821/* Mixer combinations
3822 *
3823 * basic: base_output + input + pc_beep + capture
3824 * HP: base_output + input + capture_alt
3825 * HP_3013: hp_3013 + input + capture
3826 * fujitsu: fujitsu + capture
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01003827 * acer: acer + capture
Kailang Yangdf694da2005-12-05 19:42:22 +01003828 */
3829
3830static struct snd_kcontrol_new alc260_base_output_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02003831 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003832 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01003833 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
3834 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
3835 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
3836 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
3837 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003838};
Kailang Yangdf694da2005-12-05 19:42:22 +01003839
3840static struct snd_kcontrol_new alc260_input_mixer[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003841 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
3842 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
3843 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
3844 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
3845 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
3846 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
3847 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
3848 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003849 { } /* end */
3850};
3851
Kailang Yangdf694da2005-12-05 19:42:22 +01003852static struct snd_kcontrol_new alc260_pc_beep_mixer[] = {
3853 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x07, 0x05, HDA_INPUT),
3854 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x07, 0x05, HDA_INPUT),
3855 { } /* end */
3856};
3857
Takashi Iwaibec15c32008-01-28 18:16:30 +01003858/* update HP, line and mono out pins according to the master switch */
3859static void alc260_hp_master_update(struct hda_codec *codec,
3860 hda_nid_t hp, hda_nid_t line,
3861 hda_nid_t mono)
3862{
3863 struct alc_spec *spec = codec->spec;
3864 unsigned int val = spec->master_sw ? PIN_HP : 0;
3865 /* change HP and line-out pins */
3866 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
3867 val);
3868 snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
3869 val);
3870 /* mono (speaker) depending on the HP jack sense */
3871 val = (val && !spec->jack_present) ? PIN_OUT : 0;
3872 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
3873 val);
3874}
3875
3876static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
3877 struct snd_ctl_elem_value *ucontrol)
3878{
3879 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3880 struct alc_spec *spec = codec->spec;
3881 *ucontrol->value.integer.value = spec->master_sw;
3882 return 0;
3883}
3884
3885static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
3886 struct snd_ctl_elem_value *ucontrol)
3887{
3888 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3889 struct alc_spec *spec = codec->spec;
3890 int val = !!*ucontrol->value.integer.value;
3891 hda_nid_t hp, line, mono;
3892
3893 if (val == spec->master_sw)
3894 return 0;
3895 spec->master_sw = val;
3896 hp = (kcontrol->private_value >> 16) & 0xff;
3897 line = (kcontrol->private_value >> 8) & 0xff;
3898 mono = kcontrol->private_value & 0xff;
3899 alc260_hp_master_update(codec, hp, line, mono);
3900 return 1;
3901}
3902
3903static struct snd_kcontrol_new alc260_hp_output_mixer[] = {
3904 {
3905 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3906 .name = "Master Playback Switch",
3907 .info = snd_ctl_boolean_mono_info,
3908 .get = alc260_hp_master_sw_get,
3909 .put = alc260_hp_master_sw_put,
3910 .private_value = (0x0f << 16) | (0x10 << 8) | 0x11
3911 },
3912 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
3913 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
3914 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
3915 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
3916 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
3917 HDA_OUTPUT),
3918 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT),
3919 { } /* end */
3920};
3921
3922static struct hda_verb alc260_hp_unsol_verbs[] = {
3923 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3924 {},
3925};
3926
3927static void alc260_hp_automute(struct hda_codec *codec)
3928{
3929 struct alc_spec *spec = codec->spec;
3930 unsigned int present;
3931
3932 present = snd_hda_codec_read(codec, 0x10, 0,
3933 AC_VERB_GET_PIN_SENSE, 0);
3934 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
3935 alc260_hp_master_update(codec, 0x0f, 0x10, 0x11);
3936}
3937
3938static void alc260_hp_unsol_event(struct hda_codec *codec, unsigned int res)
3939{
3940 if ((res >> 26) == ALC880_HP_EVENT)
3941 alc260_hp_automute(codec);
3942}
3943
Kailang Yangdf694da2005-12-05 19:42:22 +01003944static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01003945 {
3946 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3947 .name = "Master Playback Switch",
3948 .info = snd_ctl_boolean_mono_info,
3949 .get = alc260_hp_master_sw_get,
3950 .put = alc260_hp_master_sw_put,
3951 .private_value = (0x10 << 16) | (0x15 << 8) | 0x11
3952 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003953 HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
3954 HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
3955 HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
3956 HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
3957 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
3958 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01003959 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
3960 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003961 { } /* end */
3962};
3963
Takashi Iwaibec15c32008-01-28 18:16:30 +01003964static struct hda_verb alc260_hp_3013_unsol_verbs[] = {
3965 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3966 {},
3967};
3968
3969static void alc260_hp_3013_automute(struct hda_codec *codec)
3970{
3971 struct alc_spec *spec = codec->spec;
3972 unsigned int present;
3973
3974 present = snd_hda_codec_read(codec, 0x15, 0,
3975 AC_VERB_GET_PIN_SENSE, 0);
3976 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
3977 alc260_hp_master_update(codec, 0x10, 0x15, 0x11);
3978}
3979
3980static void alc260_hp_3013_unsol_event(struct hda_codec *codec,
3981 unsigned int res)
3982{
3983 if ((res >> 26) == ALC880_HP_EVENT)
3984 alc260_hp_3013_automute(codec);
3985}
3986
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003987/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12,
3988 * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10.
3989 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003990static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003991 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003992 HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003993 ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003994 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
3995 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
3996 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
3997 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003998 ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003999 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4000 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004001 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4002 HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01004003 { } /* end */
4004};
4005
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004006/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current
4007 * versions of the ALC260 don't act on requests to enable mic bias from NID
4008 * 0x0f (used to drive the headphone jack in these laptops). The ALC260
4009 * datasheet doesn't mention this restriction. At this stage it's not clear
4010 * whether this behaviour is intentional or is a hardware bug in chip
4011 * revisions available in early 2006. Therefore for now allow the
4012 * "Headphone Jack Mode" control to span all choices, but if it turns out
4013 * that the lack of mic bias for this NID is intentional we could change the
4014 * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
4015 *
4016 * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
4017 * don't appear to make the mic bias available from the "line" jack, even
4018 * though the NID used for this jack (0x14) can supply it. The theory is
4019 * that perhaps Acer have included blocking capacitors between the ALC260
4020 * and the output jack. If this turns out to be the case for all such
4021 * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
4022 * to ALC_PIN_DIR_INOUT_NOMICBIAS.
Jonathan Woithebd869482006-11-28 11:35:52 +01004023 *
4024 * The C20x Tablet series have a mono internal speaker which is controlled
4025 * via the chip's Mono sum widget and pin complex, so include the necessary
4026 * controls for such models. On models without a "mono speaker" the control
4027 * won't do anything.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004028 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004029static struct snd_kcontrol_new alc260_acer_mixer[] = {
4030 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4031 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004032 ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004033 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
Jonathan Woithebd869482006-11-28 11:35:52 +01004034 HDA_OUTPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004035 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2,
Jonathan Woithebd869482006-11-28 11:35:52 +01004036 HDA_INPUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004037 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4038 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4039 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4040 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4041 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4042 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4043 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4044 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4045 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4046 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
4047 { } /* end */
4048};
4049
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004050/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
4051 * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17.
4052 */
4053static struct snd_kcontrol_new alc260_will_mixer[] = {
4054 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4055 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
4056 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4057 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4058 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4059 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4060 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4061 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4062 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4063 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4064 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4065 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
4066 { } /* end */
4067};
4068
4069/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
4070 * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
4071 */
4072static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
4073 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4074 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
4075 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4076 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4077 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4078 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
4079 HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
4080 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4081 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4082 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4083 { } /* end */
4084};
4085
Kailang Yangdf694da2005-12-05 19:42:22 +01004086/* capture mixer elements */
4087static struct snd_kcontrol_new alc260_capture_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004088 HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT),
4089 HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01004090 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x05, 0x0, HDA_INPUT),
4091 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x05, 0x0, HDA_INPUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004092 {
4093 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Kailang Yangdf694da2005-12-05 19:42:22 +01004094 /* The multiple "Capture Source" controls confuse alsamixer
4095 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01004096 */
4097 /* .name = "Capture Source", */
4098 .name = "Input Source",
4099 .count = 2,
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004100 .info = alc_mux_enum_info,
4101 .get = alc_mux_enum_get,
4102 .put = alc_mux_enum_put,
4103 },
4104 { } /* end */
4105};
4106
Kailang Yangdf694da2005-12-05 19:42:22 +01004107static struct snd_kcontrol_new alc260_capture_alt_mixer[] = {
4108 HDA_CODEC_VOLUME("Capture Volume", 0x05, 0x0, HDA_INPUT),
4109 HDA_CODEC_MUTE("Capture Switch", 0x05, 0x0, HDA_INPUT),
4110 {
4111 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4112 /* The multiple "Capture Source" controls confuse alsamixer
4113 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01004114 */
4115 /* .name = "Capture Source", */
4116 .name = "Input Source",
4117 .count = 1,
4118 .info = alc_mux_enum_info,
4119 .get = alc_mux_enum_get,
4120 .put = alc_mux_enum_put,
4121 },
4122 { } /* end */
4123};
4124
4125/*
4126 * initialization verbs
4127 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004128static struct hda_verb alc260_init_verbs[] = {
4129 /* Line In pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02004130 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004131 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02004132 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004133 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02004134 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004135 /* Mic2 (front panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02004136 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137 /* LINE-2 is used for line-out in rear */
Takashi Iwai05acb862005-06-10 19:50:25 +02004138 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004139 /* select line-out */
Jonathan Woithefd56f2d2006-01-24 10:35:46 +01004140 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004141 /* LINE-OUT pin */
Takashi Iwai05acb862005-06-10 19:50:25 +02004142 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004143 /* enable HP */
Takashi Iwai05acb862005-06-10 19:50:25 +02004144 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145 /* enable Mono */
Takashi Iwai05acb862005-06-10 19:50:25 +02004146 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4147 /* mute capture amp left and right */
Takashi Iwai16ded522005-06-10 19:58:24 +02004148 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004149 /* set connection select to line in (default select for this ADC) */
4150 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai16ded522005-06-10 19:58:24 +02004151 /* mute capture amp left and right */
4152 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4153 /* set connection select to line in (default select for this ADC) */
4154 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai05acb862005-06-10 19:50:25 +02004155 /* set vol=0 Line-Out mixer amp left and right */
4156 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4157 /* unmute pin widget amp left and right (no gain on this amp) */
4158 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4159 /* set vol=0 HP mixer amp left and right */
4160 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4161 /* unmute pin widget amp left and right (no gain on this amp) */
4162 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4163 /* set vol=0 Mono mixer amp left and right */
4164 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4165 /* unmute pin widget amp left and right (no gain on this amp) */
4166 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4167 /* unmute LINE-2 out pin */
4168 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004169 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4170 * Line In 2 = 0x03
4171 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004172 /* mute analog inputs */
4173 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4174 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4175 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4176 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4177 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004178 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004179 /* mute Front out path */
4180 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4181 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4182 /* mute Headphone out path */
4183 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4184 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4185 /* mute Mono out path */
4186 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4187 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004188 { }
4189};
4190
Takashi Iwai474167d2006-05-17 17:17:43 +02004191#if 0 /* should be identical with alc260_init_verbs? */
Kailang Yangdf694da2005-12-05 19:42:22 +01004192static struct hda_verb alc260_hp_init_verbs[] = {
4193 /* Headphone and output */
4194 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
4195 /* mono output */
4196 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4197 /* Mic1 (rear panel) pin widget for input and vref at 80% */
4198 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4199 /* Mic2 (front panel) pin widget for input and vref at 80% */
4200 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4201 /* Line In pin widget for input */
4202 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4203 /* Line-2 pin widget for output */
4204 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4205 /* CD pin widget for input */
4206 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4207 /* unmute amp left and right */
4208 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
4209 /* set connection select to line in (default select for this ADC) */
4210 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
4211 /* unmute Line-Out mixer amp left and right (volume = 0) */
4212 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4213 /* mute pin widget amp left and right (no gain on this amp) */
4214 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
4215 /* unmute HP mixer amp left and right (volume = 0) */
4216 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4217 /* mute pin widget amp left and right (no gain on this amp) */
4218 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004219 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4220 * Line In 2 = 0x03
4221 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004222 /* mute analog inputs */
4223 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4224 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4225 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4226 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4227 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01004228 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
4229 /* Unmute Front out path */
4230 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4231 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4232 /* Unmute Headphone out path */
4233 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4234 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4235 /* Unmute Mono out path */
4236 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4237 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4238 { }
4239};
Takashi Iwai474167d2006-05-17 17:17:43 +02004240#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01004241
4242static struct hda_verb alc260_hp_3013_init_verbs[] = {
4243 /* Line out and output */
4244 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4245 /* mono output */
4246 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4247 /* Mic1 (rear panel) pin widget for input and vref at 80% */
4248 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4249 /* Mic2 (front panel) pin widget for input and vref at 80% */
4250 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4251 /* Line In pin widget for input */
4252 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4253 /* Headphone pin widget for output */
4254 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
4255 /* CD pin widget for input */
4256 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4257 /* unmute amp left and right */
4258 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
4259 /* set connection select to line in (default select for this ADC) */
4260 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
4261 /* unmute Line-Out mixer amp left and right (volume = 0) */
4262 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4263 /* mute pin widget amp left and right (no gain on this amp) */
4264 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
4265 /* unmute HP mixer amp left and right (volume = 0) */
4266 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4267 /* mute pin widget amp left and right (no gain on this amp) */
4268 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004269 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4270 * Line In 2 = 0x03
4271 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004272 /* mute analog inputs */
4273 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4274 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4275 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4276 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4277 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01004278 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
4279 /* Unmute Front out path */
4280 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4281 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4282 /* Unmute Headphone out path */
4283 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4284 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4285 /* Unmute Mono out path */
4286 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4287 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4288 { }
4289};
4290
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004291/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004292 * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
4293 * audio = 0x16, internal speaker = 0x10.
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004294 */
4295static struct hda_verb alc260_fujitsu_init_verbs[] = {
4296 /* Disable all GPIOs */
4297 {0x01, AC_VERB_SET_GPIO_MASK, 0},
4298 /* Internal speaker is connected to headphone pin */
4299 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4300 /* Headphone/Line-out jack connects to Line1 pin; make it an output */
4301 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004302 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
4303 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4304 /* Ensure all other unused pins are disabled and muted. */
4305 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4306 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004307 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004308 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004309 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004310 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4311 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4312 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004313
Jonathan Woithef7ace402006-02-28 11:46:14 +01004314 /* Disable digital (SPDIF) pins */
4315 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
4316 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004317
Jonathan Woithef7ace402006-02-28 11:46:14 +01004318 /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
4319 * when acting as an output.
4320 */
4321 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
4322
4323 /* Start with output sum widgets muted and their output gains at min */
Takashi Iwai8b33a5a2006-02-09 11:57:01 +01004324 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4325 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4326 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4327 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4328 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4329 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4330 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4331 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4332 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004333
Jonathan Woithef7ace402006-02-28 11:46:14 +01004334 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
4335 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4336 /* Unmute Line1 pin widget output buffer since it starts as an output.
4337 * If the pin mode is changed by the user the pin mode control will
4338 * take care of enabling the pin's input/output buffers as needed.
4339 * Therefore there's no need to enable the input buffer at this
4340 * stage.
Jonathan Woithecdcd9262006-02-28 11:36:42 +01004341 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01004342 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithecdcd9262006-02-28 11:36:42 +01004343 /* Unmute input buffer of pin widget used for Line-in (no equiv
4344 * mixer ctrl)
4345 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01004346 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004347
Jonathan Woithef7ace402006-02-28 11:46:14 +01004348 /* Mute capture amp left and right */
4349 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4350 /* Set ADC connection select to match default mixer setting - line
4351 * in (on mic1 pin)
4352 */
4353 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004354
Jonathan Woithef7ace402006-02-28 11:46:14 +01004355 /* Do the same for the second ADC: mute capture input amp and
4356 * set ADC connection to line in (on mic1 pin)
4357 */
4358 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4359 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004360
Jonathan Woithef7ace402006-02-28 11:46:14 +01004361 /* Mute all inputs to mixer widget (even unconnected ones) */
4362 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
4363 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
4364 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
4365 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
4366 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
4367 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
4368 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
4369 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
Takashi Iwai4a471b72005-12-07 13:56:29 +01004370
4371 { }
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004372};
4373
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004374/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
4375 * similar laptops (adapted from Fujitsu init verbs).
4376 */
4377static struct hda_verb alc260_acer_init_verbs[] = {
4378 /* On TravelMate laptops, GPIO 0 enables the internal speaker and
4379 * the headphone jack. Turn this on and rely on the standard mute
4380 * methods whenever the user wants to turn these outputs off.
4381 */
4382 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
4383 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
4384 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
4385 /* Internal speaker/Headphone jack is connected to Line-out pin */
4386 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4387 /* Internal microphone/Mic jack is connected to Mic1 pin */
4388 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
4389 /* Line In jack is connected to Line1 pin */
4390 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Jonathan Woithebd869482006-11-28 11:35:52 +01004391 /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
4392 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004393 /* Ensure all other unused pins are disabled and muted. */
4394 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4395 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004396 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4397 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4398 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4399 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4400 /* Disable digital (SPDIF) pins */
4401 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
4402 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
4403
4404 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
4405 * bus when acting as outputs.
4406 */
4407 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
4408 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
4409
4410 /* Start with output sum widgets muted and their output gains at min */
4411 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4412 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4413 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4414 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4415 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4416 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4417 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4418 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4419 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4420
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004421 /* Unmute Line-out pin widget amp left and right
4422 * (no equiv mixer ctrl)
4423 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004424 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithebd869482006-11-28 11:35:52 +01004425 /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
4426 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004427 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
4428 * inputs. If the pin mode is changed by the user the pin mode control
4429 * will take care of enabling the pin's input/output buffers as needed.
4430 * Therefore there's no need to enable the input buffer at this
4431 * stage.
4432 */
4433 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4434 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4435
4436 /* Mute capture amp left and right */
4437 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4438 /* Set ADC connection select to match default mixer setting - mic
4439 * (on mic1 pin)
4440 */
4441 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
4442
4443 /* Do similar with the second ADC: mute capture input amp and
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004444 * set ADC connection to mic to match ALSA's default state.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004445 */
4446 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004447 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004448
4449 /* Mute all inputs to mixer widget (even unconnected ones) */
4450 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
4451 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
4452 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
4453 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
4454 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
4455 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
4456 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
4457 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
4458
4459 { }
4460};
4461
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004462static struct hda_verb alc260_will_verbs[] = {
4463 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4464 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
4465 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
4466 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
4467 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
4468 {0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
4469 {}
4470};
4471
4472static struct hda_verb alc260_replacer_672v_verbs[] = {
4473 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
4474 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
4475 {0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
4476
4477 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
4478 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
4479 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
4480
4481 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4482 {}
4483};
4484
4485/* toggle speaker-output according to the hp-jack state */
4486static void alc260_replacer_672v_automute(struct hda_codec *codec)
4487{
4488 unsigned int present;
4489
4490 /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
4491 present = snd_hda_codec_read(codec, 0x0f, 0,
4492 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
4493 if (present) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004494 snd_hda_codec_write_cache(codec, 0x01, 0,
4495 AC_VERB_SET_GPIO_DATA, 1);
4496 snd_hda_codec_write_cache(codec, 0x0f, 0,
4497 AC_VERB_SET_PIN_WIDGET_CONTROL,
4498 PIN_HP);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004499 } else {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004500 snd_hda_codec_write_cache(codec, 0x01, 0,
4501 AC_VERB_SET_GPIO_DATA, 0);
4502 snd_hda_codec_write_cache(codec, 0x0f, 0,
4503 AC_VERB_SET_PIN_WIDGET_CONTROL,
4504 PIN_OUT);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004505 }
4506}
4507
4508static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
4509 unsigned int res)
4510{
4511 if ((res >> 26) == ALC880_HP_EVENT)
4512 alc260_replacer_672v_automute(codec);
4513}
4514
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004515/* Test configuration for debugging, modelled after the ALC880 test
4516 * configuration.
4517 */
4518#ifdef CONFIG_SND_DEBUG
4519static hda_nid_t alc260_test_dac_nids[1] = {
4520 0x02,
4521};
4522static hda_nid_t alc260_test_adc_nids[2] = {
4523 0x04, 0x05,
4524};
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004525/* For testing the ALC260, each input MUX needs its own definition since
4526 * the signal assignments are different. This assumes that the first ADC
4527 * is NID 0x04.
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01004528 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004529static struct hda_input_mux alc260_test_capture_sources[2] = {
4530 {
4531 .num_items = 7,
4532 .items = {
4533 { "MIC1 pin", 0x0 },
4534 { "MIC2 pin", 0x1 },
4535 { "LINE1 pin", 0x2 },
4536 { "LINE2 pin", 0x3 },
4537 { "CD pin", 0x4 },
4538 { "LINE-OUT pin", 0x5 },
4539 { "HP-OUT pin", 0x6 },
4540 },
4541 },
4542 {
4543 .num_items = 8,
4544 .items = {
4545 { "MIC1 pin", 0x0 },
4546 { "MIC2 pin", 0x1 },
4547 { "LINE1 pin", 0x2 },
4548 { "LINE2 pin", 0x3 },
4549 { "CD pin", 0x4 },
4550 { "Mixer", 0x5 },
4551 { "LINE-OUT pin", 0x6 },
4552 { "HP-OUT pin", 0x7 },
4553 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004554 },
4555};
4556static struct snd_kcontrol_new alc260_test_mixer[] = {
4557 /* Output driver widgets */
4558 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
4559 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
4560 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4561 HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
4562 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4563 HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
4564
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004565 /* Modes for retasking pin widgets
4566 * Note: the ALC260 doesn't seem to act on requests to enable mic
4567 * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't
4568 * mention this restriction. At this stage it's not clear whether
4569 * this behaviour is intentional or is a hardware bug in chip
4570 * revisions available at least up until early 2006. Therefore for
4571 * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
4572 * choices, but if it turns out that the lack of mic bias for these
4573 * NIDs is intentional we could change their modes from
4574 * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
4575 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004576 ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
4577 ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
4578 ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
4579 ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
4580 ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
4581 ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
4582
4583 /* Loopback mixer controls */
4584 HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
4585 HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
4586 HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
4587 HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
4588 HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
4589 HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
4590 HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
4591 HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
4592 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4593 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4594 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4595 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
4596 HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
4597 HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
4598 HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
4599 HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01004600
4601 /* Controls for GPIO pins, assuming they are configured as outputs */
4602 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
4603 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
4604 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
4605 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
4606
Jonathan Woithe92621f12006-02-28 11:47:47 +01004607 /* Switches to allow the digital IO pins to be enabled. The datasheet
4608 * is ambigious as to which NID is which; testing on laptops which
4609 * make this output available should provide clarification.
4610 */
4611 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
4612 ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
4613
Jonathan Woithef8225f62008-01-08 12:16:54 +01004614 /* A switch allowing EAPD to be enabled. Some laptops seem to use
4615 * this output to turn on an external amplifier.
4616 */
4617 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
4618 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
4619
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004620 { } /* end */
4621};
4622static struct hda_verb alc260_test_init_verbs[] = {
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01004623 /* Enable all GPIOs as outputs with an initial value of 0 */
4624 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
4625 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
4626 {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
4627
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004628 /* Enable retasking pins as output, initially without power amp */
4629 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4630 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4631 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4632 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4633 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4634 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4635
Jonathan Woithe92621f12006-02-28 11:47:47 +01004636 /* Disable digital (SPDIF) pins initially, but users can enable
4637 * them via a mixer switch. In the case of SPDIF-out, this initverb
4638 * payload also sets the generation to 0, output to be in "consumer"
4639 * PCM format, copyright asserted, no pre-emphasis and no validity
4640 * control.
4641 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004642 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
4643 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
4644
Jonathan Woithef7ace402006-02-28 11:46:14 +01004645 /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004646 * OUT1 sum bus when acting as an output.
4647 */
4648 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
4649 {0x0c, AC_VERB_SET_CONNECT_SEL, 0},
4650 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
4651 {0x0e, AC_VERB_SET_CONNECT_SEL, 0},
4652
4653 /* Start with output sum widgets muted and their output gains at min */
4654 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4655 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4656 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4657 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4658 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4659 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4660 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4661 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4662 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4663
Jonathan Woithecdcd9262006-02-28 11:36:42 +01004664 /* Unmute retasking pin widget output buffers since the default
4665 * state appears to be output. As the pin mode is changed by the
4666 * user the pin mode control will take care of enabling the pin's
4667 * input/output buffers as needed.
4668 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004669 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4670 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4671 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4672 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4673 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4674 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4675 /* Also unmute the mono-out pin widget */
4676 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4677
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004678 /* Mute capture amp left and right */
4679 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004680 /* Set ADC connection select to match default mixer setting (mic1
4681 * pin)
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004682 */
4683 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
4684
4685 /* Do the same for the second ADC: mute capture input amp and
Jonathan Woithef7ace402006-02-28 11:46:14 +01004686 * set ADC connection to mic1 pin
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004687 */
4688 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4689 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
4690
4691 /* Mute all inputs to mixer widget (even unconnected ones) */
4692 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
4693 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
4694 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
4695 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
4696 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
4697 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
4698 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
4699 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
4700
4701 { }
4702};
4703#endif
4704
Takashi Iwai63300792008-01-24 15:31:36 +01004705#define alc260_pcm_analog_playback alc880_pcm_analog_alt_playback
4706#define alc260_pcm_analog_capture alc880_pcm_analog_capture
Linus Torvalds1da177e2005-04-16 15:20:36 -07004707
Takashi Iwaia3bcba32005-12-06 19:05:29 +01004708#define alc260_pcm_digital_playback alc880_pcm_digital_playback
4709#define alc260_pcm_digital_capture alc880_pcm_digital_capture
4710
Kailang Yangdf694da2005-12-05 19:42:22 +01004711/*
4712 * for BIOS auto-configuration
4713 */
4714
4715static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
4716 const char *pfx)
4717{
4718 hda_nid_t nid_vol;
4719 unsigned long vol_val, sw_val;
4720 char name[32];
4721 int err;
4722
4723 if (nid >= 0x0f && nid < 0x11) {
4724 nid_vol = nid - 0x7;
4725 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
4726 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
4727 } else if (nid == 0x11) {
4728 nid_vol = nid - 0x7;
4729 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT);
4730 sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
4731 } else if (nid >= 0x12 && nid <= 0x15) {
4732 nid_vol = 0x08;
4733 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
4734 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
4735 } else
4736 return 0; /* N/A */
4737
4738 snprintf(name, sizeof(name), "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004739 err = add_control(spec, ALC_CTL_WIDGET_VOL, name, vol_val);
4740 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01004741 return err;
4742 snprintf(name, sizeof(name), "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004743 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, sw_val);
4744 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01004745 return err;
4746 return 1;
4747}
4748
4749/* add playback controls from the parsed DAC table */
4750static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
4751 const struct auto_pin_cfg *cfg)
4752{
4753 hda_nid_t nid;
4754 int err;
4755
4756 spec->multiout.num_dacs = 1;
4757 spec->multiout.dac_nids = spec->private_dac_nids;
4758 spec->multiout.dac_nids[0] = 0x02;
4759
4760 nid = cfg->line_out_pins[0];
4761 if (nid) {
4762 err = alc260_add_playback_controls(spec, nid, "Front");
4763 if (err < 0)
4764 return err;
4765 }
4766
Takashi Iwai82bc9552006-03-21 11:24:42 +01004767 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01004768 if (nid) {
4769 err = alc260_add_playback_controls(spec, nid, "Speaker");
4770 if (err < 0)
4771 return err;
4772 }
4773
Takashi Iwaieb06ed82006-09-20 17:10:27 +02004774 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01004775 if (nid) {
4776 err = alc260_add_playback_controls(spec, nid, "Headphone");
4777 if (err < 0)
4778 return err;
4779 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004780 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01004781}
4782
4783/* create playback/capture controls for input pins */
4784static int alc260_auto_create_analog_input_ctls(struct alc_spec *spec,
4785 const struct auto_pin_cfg *cfg)
4786{
Kailang Yangdf694da2005-12-05 19:42:22 +01004787 struct hda_input_mux *imux = &spec->private_imux;
4788 int i, err, idx;
4789
4790 for (i = 0; i < AUTO_PIN_LAST; i++) {
4791 if (cfg->input_pins[i] >= 0x12) {
4792 idx = cfg->input_pins[i] - 0x12;
Takashi Iwai4a471b72005-12-07 13:56:29 +01004793 err = new_analog_input(spec, cfg->input_pins[i],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004794 auto_pin_cfg_labels[i], idx,
4795 0x07);
Kailang Yangdf694da2005-12-05 19:42:22 +01004796 if (err < 0)
4797 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004798 imux->items[imux->num_items].label =
4799 auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +01004800 imux->items[imux->num_items].index = idx;
4801 imux->num_items++;
4802 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004803 if (cfg->input_pins[i] >= 0x0f && cfg->input_pins[i] <= 0x10){
Kailang Yangdf694da2005-12-05 19:42:22 +01004804 idx = cfg->input_pins[i] - 0x09;
Takashi Iwai4a471b72005-12-07 13:56:29 +01004805 err = new_analog_input(spec, cfg->input_pins[i],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004806 auto_pin_cfg_labels[i], idx,
4807 0x07);
Kailang Yangdf694da2005-12-05 19:42:22 +01004808 if (err < 0)
4809 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004810 imux->items[imux->num_items].label =
4811 auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +01004812 imux->items[imux->num_items].index = idx;
4813 imux->num_items++;
4814 }
4815 }
4816 return 0;
4817}
4818
4819static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
4820 hda_nid_t nid, int pin_type,
4821 int sel_idx)
4822{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004823 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01004824 /* need the manual connection? */
4825 if (nid >= 0x12) {
4826 int idx = nid - 0x12;
4827 snd_hda_codec_write(codec, idx + 0x0b, 0,
4828 AC_VERB_SET_CONNECT_SEL, sel_idx);
Kailang Yangdf694da2005-12-05 19:42:22 +01004829 }
4830}
4831
4832static void alc260_auto_init_multi_out(struct hda_codec *codec)
4833{
4834 struct alc_spec *spec = codec->spec;
4835 hda_nid_t nid;
4836
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004837 alc_subsystem_id(codec, 0x10, 0x15, 0x0f);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004838 nid = spec->autocfg.line_out_pins[0];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02004839 if (nid) {
4840 int pin_type = get_pin_type(spec->autocfg.line_out_type);
4841 alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
4842 }
Kailang Yangdf694da2005-12-05 19:42:22 +01004843
Takashi Iwai82bc9552006-03-21 11:24:42 +01004844 nid = spec->autocfg.speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01004845 if (nid)
4846 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
4847
Takashi Iwaieb06ed82006-09-20 17:10:27 +02004848 nid = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01004849 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02004850 alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004851}
Kailang Yangdf694da2005-12-05 19:42:22 +01004852
4853#define ALC260_PIN_CD_NID 0x16
4854static void alc260_auto_init_analog_input(struct hda_codec *codec)
4855{
4856 struct alc_spec *spec = codec->spec;
4857 int i;
4858
4859 for (i = 0; i < AUTO_PIN_LAST; i++) {
4860 hda_nid_t nid = spec->autocfg.input_pins[i];
4861 if (nid >= 0x12) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004862 snd_hda_codec_write(codec, nid, 0,
4863 AC_VERB_SET_PIN_WIDGET_CONTROL,
4864 i <= AUTO_PIN_FRONT_MIC ?
4865 PIN_VREF80 : PIN_IN);
Kailang Yangdf694da2005-12-05 19:42:22 +01004866 if (nid != ALC260_PIN_CD_NID)
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004867 snd_hda_codec_write(codec, nid, 0,
4868 AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangdf694da2005-12-05 19:42:22 +01004869 AMP_OUT_MUTE);
4870 }
4871 }
4872}
4873
4874/*
4875 * generic initialization of ADC, input mixers and output mixers
4876 */
4877static struct hda_verb alc260_volume_init_verbs[] = {
4878 /*
4879 * Unmute ADC0-1 and set the default input to mic-in
4880 */
4881 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
4882 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4883 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
4884 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4885
4886 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
4887 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004888 * Note: PASD motherboards uses the Line In 2 as the input for
4889 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01004890 */
4891 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004892 /* mute analog inputs */
4893 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4894 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4895 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4896 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4897 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01004898
4899 /*
4900 * Set up output mixers (0x08 - 0x0a)
4901 */
4902 /* set vol=0 to output mixers */
4903 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4904 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4905 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4906 /* set up input amps for analog loopback */
4907 /* Amp Indices: DAC = 0, mixer = 1 */
4908 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4909 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4910 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4911 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4912 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4913 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4914
4915 { }
4916};
4917
4918static int alc260_parse_auto_config(struct hda_codec *codec)
4919{
4920 struct alc_spec *spec = codec->spec;
4921 unsigned int wcap;
4922 int err;
4923 static hda_nid_t alc260_ignore[] = { 0x17, 0 };
4924
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004925 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
4926 alc260_ignore);
4927 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01004928 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004929 err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
4930 if (err < 0)
Takashi Iwai4a471b72005-12-07 13:56:29 +01004931 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004932 if (!spec->kctl_alloc)
Kailang Yangdf694da2005-12-05 19:42:22 +01004933 return 0; /* can't find valid BIOS pin config */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004934 err = alc260_auto_create_analog_input_ctls(spec, &spec->autocfg);
4935 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01004936 return err;
4937
4938 spec->multiout.max_channels = 2;
4939
4940 if (spec->autocfg.dig_out_pin)
4941 spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
4942 if (spec->kctl_alloc)
4943 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
4944
4945 spec->init_verbs[spec->num_init_verbs++] = alc260_volume_init_verbs;
4946
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004947 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +01004948 spec->input_mux = &spec->private_imux;
4949
4950 /* check whether NID 0x04 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +01004951 wcap = get_wcaps(codec, 0x04);
Kailang Yangdf694da2005-12-05 19:42:22 +01004952 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */
4953 if (wcap != AC_WID_AUD_IN) {
4954 spec->adc_nids = alc260_adc_nids_alt;
4955 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
4956 spec->mixers[spec->num_mixers] = alc260_capture_alt_mixer;
Kailang Yangdf694da2005-12-05 19:42:22 +01004957 } else {
4958 spec->adc_nids = alc260_adc_nids;
4959 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
4960 spec->mixers[spec->num_mixers] = alc260_capture_mixer;
Kailang Yangdf694da2005-12-05 19:42:22 +01004961 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01004962 spec->num_mixers++;
Kailang Yangdf694da2005-12-05 19:42:22 +01004963
4964 return 1;
4965}
4966
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004967/* additional initialization for auto-configuration model */
4968static void alc260_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01004969{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004970 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01004971 alc260_auto_init_multi_out(codec);
4972 alc260_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004973 if (spec->unsol_event)
4974 alc_sku_automute(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01004975}
4976
Takashi Iwaicb53c622007-08-10 17:21:45 +02004977#ifdef CONFIG_SND_HDA_POWER_SAVE
4978static struct hda_amp_list alc260_loopbacks[] = {
4979 { 0x07, HDA_INPUT, 0 },
4980 { 0x07, HDA_INPUT, 1 },
4981 { 0x07, HDA_INPUT, 2 },
4982 { 0x07, HDA_INPUT, 3 },
4983 { 0x07, HDA_INPUT, 4 },
4984 { } /* end */
4985};
4986#endif
4987
Kailang Yangdf694da2005-12-05 19:42:22 +01004988/*
4989 * ALC260 configurations
4990 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004991static const char *alc260_models[ALC260_MODEL_LAST] = {
4992 [ALC260_BASIC] = "basic",
4993 [ALC260_HP] = "hp",
4994 [ALC260_HP_3013] = "hp-3013",
4995 [ALC260_FUJITSU_S702X] = "fujitsu",
4996 [ALC260_ACER] = "acer",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004997 [ALC260_WILL] = "will",
4998 [ALC260_REPLACER_672V] = "replacer",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004999#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005000 [ALC260_TEST] = "test",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005001#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005002 [ALC260_AUTO] = "auto",
5003};
5004
5005static struct snd_pci_quirk alc260_cfg_tbl[] = {
Jonathan Woithebd869482006-11-28 11:35:52 +01005006 SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005007 SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
Takashi Iwai9720b712007-03-13 21:46:23 +01005008 SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
Takashi Iwaia8a5d062007-03-15 15:10:28 +01005009 SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_HP_3013),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005010 SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
5011 SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP),
5012 SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_3013),
5013 SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
5014 SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
5015 SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
5016 SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
5017 SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
5018 SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
5019 SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
5020 SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
5021 SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005022 SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01005023 SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
Takashi Iwai16ded522005-06-10 19:58:24 +02005024 {}
5025};
5026
Kailang Yangdf694da2005-12-05 19:42:22 +01005027static struct alc_config_preset alc260_presets[] = {
5028 [ALC260_BASIC] = {
5029 .mixers = { alc260_base_output_mixer,
5030 alc260_input_mixer,
5031 alc260_pc_beep_mixer,
5032 alc260_capture_mixer },
5033 .init_verbs = { alc260_init_verbs },
5034 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5035 .dac_nids = alc260_dac_nids,
5036 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
5037 .adc_nids = alc260_adc_nids,
5038 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5039 .channel_mode = alc260_modes,
5040 .input_mux = &alc260_capture_source,
5041 },
5042 [ALC260_HP] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01005043 .mixers = { alc260_hp_output_mixer,
Kailang Yangdf694da2005-12-05 19:42:22 +01005044 alc260_input_mixer,
5045 alc260_capture_alt_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01005046 .init_verbs = { alc260_init_verbs,
5047 alc260_hp_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01005048 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5049 .dac_nids = alc260_dac_nids,
5050 .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
5051 .adc_nids = alc260_hp_adc_nids,
5052 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5053 .channel_mode = alc260_modes,
5054 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005055 .unsol_event = alc260_hp_unsol_event,
5056 .init_hook = alc260_hp_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01005057 },
5058 [ALC260_HP_3013] = {
5059 .mixers = { alc260_hp_3013_mixer,
5060 alc260_input_mixer,
5061 alc260_capture_alt_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01005062 .init_verbs = { alc260_hp_3013_init_verbs,
5063 alc260_hp_3013_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01005064 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5065 .dac_nids = alc260_dac_nids,
5066 .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
5067 .adc_nids = alc260_hp_adc_nids,
5068 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5069 .channel_mode = alc260_modes,
5070 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005071 .unsol_event = alc260_hp_3013_unsol_event,
5072 .init_hook = alc260_hp_3013_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01005073 },
5074 [ALC260_FUJITSU_S702X] = {
5075 .mixers = { alc260_fujitsu_mixer,
5076 alc260_capture_mixer },
5077 .init_verbs = { alc260_fujitsu_init_verbs },
5078 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5079 .dac_nids = alc260_dac_nids,
Jonathan Woithed57fdac2006-02-28 11:38:35 +01005080 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
5081 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01005082 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5083 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005084 .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
5085 .input_mux = alc260_fujitsu_capture_sources,
Kailang Yangdf694da2005-12-05 19:42:22 +01005086 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005087 [ALC260_ACER] = {
5088 .mixers = { alc260_acer_mixer,
5089 alc260_capture_mixer },
5090 .init_verbs = { alc260_acer_init_verbs },
5091 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5092 .dac_nids = alc260_dac_nids,
5093 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
5094 .adc_nids = alc260_dual_adc_nids,
5095 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5096 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005097 .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
5098 .input_mux = alc260_acer_capture_sources,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005099 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005100 [ALC260_WILL] = {
5101 .mixers = { alc260_will_mixer,
5102 alc260_capture_mixer },
5103 .init_verbs = { alc260_init_verbs, alc260_will_verbs },
5104 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5105 .dac_nids = alc260_dac_nids,
5106 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
5107 .adc_nids = alc260_adc_nids,
5108 .dig_out_nid = ALC260_DIGOUT_NID,
5109 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5110 .channel_mode = alc260_modes,
5111 .input_mux = &alc260_capture_source,
5112 },
5113 [ALC260_REPLACER_672V] = {
5114 .mixers = { alc260_replacer_672v_mixer,
5115 alc260_capture_mixer },
5116 .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
5117 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5118 .dac_nids = alc260_dac_nids,
5119 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
5120 .adc_nids = alc260_adc_nids,
5121 .dig_out_nid = ALC260_DIGOUT_NID,
5122 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5123 .channel_mode = alc260_modes,
5124 .input_mux = &alc260_capture_source,
5125 .unsol_event = alc260_replacer_672v_unsol_event,
5126 .init_hook = alc260_replacer_672v_automute,
5127 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005128#ifdef CONFIG_SND_DEBUG
5129 [ALC260_TEST] = {
5130 .mixers = { alc260_test_mixer,
5131 alc260_capture_mixer },
5132 .init_verbs = { alc260_test_init_verbs },
5133 .num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
5134 .dac_nids = alc260_test_dac_nids,
5135 .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
5136 .adc_nids = alc260_test_adc_nids,
5137 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5138 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005139 .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
5140 .input_mux = alc260_test_capture_sources,
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005141 },
5142#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01005143};
5144
Linus Torvalds1da177e2005-04-16 15:20:36 -07005145static int patch_alc260(struct hda_codec *codec)
5146{
5147 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01005148 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005149
Takashi Iwaie560d8d2005-09-09 14:21:46 +02005150 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005151 if (spec == NULL)
5152 return -ENOMEM;
5153
5154 codec->spec = spec;
5155
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005156 board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
5157 alc260_models,
5158 alc260_cfg_tbl);
5159 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02005160 snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260, "
5161 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01005162 board_config = ALC260_AUTO;
Takashi Iwai16ded522005-06-10 19:58:24 +02005163 }
5164
Kailang Yangdf694da2005-12-05 19:42:22 +01005165 if (board_config == ALC260_AUTO) {
5166 /* automatic parse from the BIOS config */
5167 err = alc260_parse_auto_config(codec);
5168 if (err < 0) {
5169 alc_free(codec);
5170 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005171 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02005172 printk(KERN_INFO
5173 "hda_codec: Cannot set up configuration "
5174 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01005175 board_config = ALC260_BASIC;
5176 }
Takashi Iwai16ded522005-06-10 19:58:24 +02005177 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005178
Kailang Yangdf694da2005-12-05 19:42:22 +01005179 if (board_config != ALC260_AUTO)
5180 setup_preset(spec, &alc260_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005181
5182 spec->stream_name_analog = "ALC260 Analog";
5183 spec->stream_analog_playback = &alc260_pcm_analog_playback;
5184 spec->stream_analog_capture = &alc260_pcm_analog_capture;
5185
Takashi Iwaia3bcba32005-12-06 19:05:29 +01005186 spec->stream_name_digital = "ALC260 Digital";
5187 spec->stream_digital_playback = &alc260_pcm_digital_playback;
5188 spec->stream_digital_capture = &alc260_pcm_digital_capture;
5189
Takashi Iwai2134ea42008-01-10 16:53:55 +01005190 spec->vmaster_nid = 0x08;
5191
Linus Torvalds1da177e2005-04-16 15:20:36 -07005192 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01005193 if (board_config == ALC260_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005194 spec->init_hook = alc260_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02005195#ifdef CONFIG_SND_HDA_POWER_SAVE
5196 if (!spec->loopback.amplist)
5197 spec->loopback.amplist = alc260_loopbacks;
5198#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005199
5200 return 0;
5201}
5202
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005203
Linus Torvalds1da177e2005-04-16 15:20:36 -07005204/*
5205 * ALC882 support
5206 *
5207 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
5208 * configuration. Each pin widget can choose any input DACs and a mixer.
5209 * Each ADC is connected from a mixer of all inputs. This makes possible
5210 * 6-channel independent captures.
5211 *
5212 * In addition, an independent DAC for the multi-playback (not used in this
5213 * driver yet).
5214 */
Kailang Yangdf694da2005-12-05 19:42:22 +01005215#define ALC882_DIGOUT_NID 0x06
5216#define ALC882_DIGIN_NID 0x0a
Linus Torvalds1da177e2005-04-16 15:20:36 -07005217
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01005218static struct hda_channel_mode alc882_ch_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005219 { 8, NULL }
5220};
5221
5222static hda_nid_t alc882_dac_nids[4] = {
5223 /* front, rear, clfe, rear_surr */
5224 0x02, 0x03, 0x04, 0x05
5225};
5226
Kailang Yangdf694da2005-12-05 19:42:22 +01005227/* identical with ALC880 */
5228#define alc882_adc_nids alc880_adc_nids
5229#define alc882_adc_nids_alt alc880_adc_nids_alt
Linus Torvalds1da177e2005-04-16 15:20:36 -07005230
Takashi Iwaie1406342008-02-11 18:32:32 +01005231static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
5232static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
5233
Linus Torvalds1da177e2005-04-16 15:20:36 -07005234/* input MUX */
5235/* FIXME: should be a matrix-type input source selection */
5236
5237static struct hda_input_mux alc882_capture_source = {
5238 .num_items = 4,
5239 .items = {
5240 { "Mic", 0x0 },
5241 { "Front Mic", 0x1 },
5242 { "Line", 0x2 },
5243 { "CD", 0x4 },
5244 },
5245};
Linus Torvalds1da177e2005-04-16 15:20:36 -07005246#define alc882_mux_enum_info alc_mux_enum_info
5247#define alc882_mux_enum_get alc_mux_enum_get
5248
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005249static int alc882_mux_enum_put(struct snd_kcontrol *kcontrol,
5250 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005251{
5252 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
5253 struct alc_spec *spec = codec->spec;
5254 const struct hda_input_mux *imux = spec->input_mux;
5255 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwaie1406342008-02-11 18:32:32 +01005256 hda_nid_t nid = spec->capsrc_nids[adc_idx];
Linus Torvalds1da177e2005-04-16 15:20:36 -07005257 unsigned int *cur_val = &spec->cur_mux[adc_idx];
5258 unsigned int i, idx;
5259
5260 idx = ucontrol->value.enumerated.item[0];
5261 if (idx >= imux->num_items)
5262 idx = imux->num_items - 1;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005263 if (*cur_val == idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005264 return 0;
5265 for (i = 0; i < imux->num_items; i++) {
Takashi Iwai47fd8302007-08-10 17:11:07 +02005266 unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
5267 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005268 imux->items[i].index,
Takashi Iwai47fd8302007-08-10 17:11:07 +02005269 HDA_AMP_MUTE, v);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005270 }
5271 *cur_val = idx;
5272 return 1;
5273}
5274
Kailang Yangdf694da2005-12-05 19:42:22 +01005275/*
Kailang Yang272a5272007-05-14 11:00:38 +02005276 * 2ch mode
5277 */
5278static struct hda_verb alc882_3ST_ch2_init[] = {
5279 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
5280 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
5281 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
5282 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
5283 { } /* end */
5284};
5285
5286/*
5287 * 6ch mode
5288 */
5289static struct hda_verb alc882_3ST_ch6_init[] = {
5290 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5291 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
5292 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
5293 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5294 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
5295 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
5296 { } /* end */
5297};
5298
5299static struct hda_channel_mode alc882_3ST_6ch_modes[2] = {
5300 { 2, alc882_3ST_ch2_init },
5301 { 6, alc882_3ST_ch6_init },
5302};
5303
5304/*
Kailang Yangdf694da2005-12-05 19:42:22 +01005305 * 6ch mode
5306 */
5307static struct hda_verb alc882_sixstack_ch6_init[] = {
5308 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
5309 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5310 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5311 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5312 { } /* end */
5313};
5314
5315/*
5316 * 8ch mode
5317 */
5318static struct hda_verb alc882_sixstack_ch8_init[] = {
5319 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5320 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5321 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5322 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5323 { } /* end */
5324};
5325
5326static struct hda_channel_mode alc882_sixstack_modes[2] = {
5327 { 6, alc882_sixstack_ch6_init },
5328 { 8, alc882_sixstack_ch8_init },
5329};
5330
Takashi Iwai87350ad2007-08-16 18:19:38 +02005331/*
5332 * macbook pro ALC885 can switch LineIn to LineOut without loosing Mic
5333 */
5334
5335/*
5336 * 2ch mode
5337 */
5338static struct hda_verb alc885_mbp_ch2_init[] = {
5339 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
5340 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5341 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5342 { } /* end */
5343};
5344
5345/*
5346 * 6ch mode
5347 */
5348static struct hda_verb alc885_mbp_ch6_init[] = {
5349 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5350 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5351 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
5352 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5353 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5354 { } /* end */
5355};
5356
5357static struct hda_channel_mode alc885_mbp_6ch_modes[2] = {
5358 { 2, alc885_mbp_ch2_init },
5359 { 6, alc885_mbp_ch6_init },
5360};
5361
5362
Linus Torvalds1da177e2005-04-16 15:20:36 -07005363/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
5364 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
5365 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01005366static struct snd_kcontrol_new alc882_base_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02005367 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005368 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005369 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005370 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005371 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
5372 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005373 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
5374 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005375 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005376 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005377 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
5378 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5379 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5380 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5381 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5382 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01005383 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005384 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5385 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01005386 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005387 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
5388 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5389 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005390 { } /* end */
5391};
5392
Takashi Iwai87350ad2007-08-16 18:19:38 +02005393static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01005394 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
5395 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
5396 HDA_CODEC_MUTE ("Speaker Playback Switch", 0x14, 0x00, HDA_OUTPUT),
5397 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
5398 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5399 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02005400 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
5401 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01005402 HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02005403 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
5404 { } /* end */
5405};
Kailang Yangbdd148a2007-05-08 15:19:08 +02005406static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
5407 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5408 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5409 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5410 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5411 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5412 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5413 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5414 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
5415 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5416 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5417 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
5418 { } /* end */
5419};
5420
Kailang Yang272a5272007-05-14 11:00:38 +02005421static struct snd_kcontrol_new alc882_targa_mixer[] = {
5422 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5423 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5424 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
5425 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5426 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5427 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5428 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5429 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5430 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02005431 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005432 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
5433 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02005434 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005435 { } /* end */
5436};
5437
5438/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
5439 * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
5440 */
5441static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
5442 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5443 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
5444 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
5445 HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT),
5446 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5447 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5448 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5449 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5450 HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
5451 HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
5452 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5453 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02005454 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005455 { } /* end */
5456};
5457
Takashi Iwai914759b2007-09-06 14:52:04 +02005458static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
5459 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5460 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5461 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
5462 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5463 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5464 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5465 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5466 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5467 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
5468 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5469 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5470 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
5471 { } /* end */
5472};
5473
Kailang Yangdf694da2005-12-05 19:42:22 +01005474static struct snd_kcontrol_new alc882_chmode_mixer[] = {
5475 {
5476 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5477 .name = "Channel Mode",
5478 .info = alc_ch_mode_info,
5479 .get = alc_ch_mode_get,
5480 .put = alc_ch_mode_put,
5481 },
5482 { } /* end */
5483};
5484
Linus Torvalds1da177e2005-04-16 15:20:36 -07005485static struct hda_verb alc882_init_verbs[] = {
5486 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005487 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5488 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5489 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005490 /* Rear mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005491 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5492 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5493 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005494 /* CLFE mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005495 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5496 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5497 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005498 /* Side mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005499 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5500 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5501 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005502
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005503 /* Front Pin: output 0 (0x0c) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005504 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005505 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005506 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005507 /* Rear Pin: output 1 (0x0d) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005508 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005509 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005510 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005511 /* CLFE Pin: output 2 (0x0e) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005512 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005513 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005514 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005515 /* Side Pin: output 3 (0x0f) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005516 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005517 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005518 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005519 /* Mic (rear) pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005520 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005521 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5522 /* Front Mic pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005523 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005524 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5525 /* Line In pin: input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005526 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005527 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5528 /* Line-2 In: Headphone output (output 0 - 0x0c) */
5529 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5530 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5531 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005532 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005533 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005534
5535 /* FIXME: use matrix-type input source selection */
5536 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
5537 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Takashi Iwai05acb862005-06-10 19:50:25 +02005538 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5539 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5540 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5541 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005542 /* Input mixer2 */
Takashi Iwai05acb862005-06-10 19:50:25 +02005543 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5544 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5545 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5546 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005547 /* Input mixer3 */
Takashi Iwai05acb862005-06-10 19:50:25 +02005548 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5549 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5550 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5551 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5552 /* ADC1: mute amp left and right */
5553 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005554 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02005555 /* ADC2: mute amp left and right */
5556 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005557 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02005558 /* ADC3: mute amp left and right */
5559 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005560 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005561
5562 { }
5563};
5564
Takashi Iwai4b146cb2006-07-28 14:42:36 +02005565static struct hda_verb alc882_eapd_verbs[] = {
5566 /* change to EAPD mode */
5567 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01005568 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005569 { }
Takashi Iwai4b146cb2006-07-28 14:42:36 +02005570};
5571
Tobin Davis9102cd12006-12-15 10:02:12 +01005572/* Mac Pro test */
5573static struct snd_kcontrol_new alc882_macpro_mixer[] = {
5574 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5575 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5576 HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
5577 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
5578 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
5579 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x02, HDA_INPUT),
5580 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x02, HDA_INPUT),
5581 { } /* end */
5582};
5583
5584static struct hda_verb alc882_macpro_init_verbs[] = {
5585 /* Front mixer: unmute input/output amp left and right (volume = 0) */
5586 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5587 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5588 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5589 /* Front Pin: output 0 (0x0c) */
5590 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5591 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5592 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
5593 /* Front Mic pin: input vref at 80% */
5594 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5595 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5596 /* Speaker: output */
5597 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5598 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5599 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
5600 /* Headphone output (output 0 - 0x0c) */
5601 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5602 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5603 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
5604
5605 /* FIXME: use matrix-type input source selection */
5606 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
5607 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
5608 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5609 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5610 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5611 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5612 /* Input mixer2 */
5613 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5614 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5615 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5616 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5617 /* Input mixer3 */
5618 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5619 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5620 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5621 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5622 /* ADC1: mute amp left and right */
5623 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5624 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
5625 /* ADC2: mute amp left and right */
5626 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5627 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
5628 /* ADC3: mute amp left and right */
5629 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5630 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
5631
5632 { }
5633};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005634
Takashi Iwai87350ad2007-08-16 18:19:38 +02005635/* Macbook Pro rev3 */
5636static struct hda_verb alc885_mbp3_init_verbs[] = {
5637 /* Front mixer: unmute input/output amp left and right (volume = 0) */
5638 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5639 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5640 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5641 /* Rear mixer */
5642 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5643 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5644 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5645 /* Front Pin: output 0 (0x0c) */
5646 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5647 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5648 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
5649 /* HP Pin: output 0 (0x0d) */
5650 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
5651 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5652 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
5653 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
5654 /* Mic (rear) pin: input vref at 80% */
5655 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5656 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5657 /* Front Mic pin: input vref at 80% */
5658 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5659 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5660 /* Line In pin: use output 1 when in LineOut mode */
5661 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
5662 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5663 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
5664
5665 /* FIXME: use matrix-type input source selection */
5666 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
5667 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
5668 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5669 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5670 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5671 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5672 /* Input mixer2 */
5673 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5674 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5675 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5676 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5677 /* Input mixer3 */
5678 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5679 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5680 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5681 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5682 /* ADC1: mute amp left and right */
5683 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5684 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
5685 /* ADC2: mute amp left and right */
5686 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5687 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
5688 /* ADC3: mute amp left and right */
5689 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5690 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
5691
5692 { }
5693};
5694
Nicola Fagnanic54728d2007-07-19 23:28:52 +02005695/* iMac 24 mixer. */
5696static struct snd_kcontrol_new alc885_imac24_mixer[] = {
5697 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
5698 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
5699 { } /* end */
5700};
5701
5702/* iMac 24 init verbs. */
5703static struct hda_verb alc885_imac24_init_verbs[] = {
5704 /* Internal speakers: output 0 (0x0c) */
5705 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5706 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5707 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
5708 /* Internal speakers: output 0 (0x0c) */
5709 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5710 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5711 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
5712 /* Headphone: output 0 (0x0c) */
5713 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5714 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5715 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
5716 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
5717 /* Front Mic: input vref at 80% */
5718 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5719 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5720 { }
5721};
5722
5723/* Toggle speaker-output according to the hp-jack state */
5724static void alc885_imac24_automute(struct hda_codec *codec)
5725{
5726 unsigned int present;
5727
5728 present = snd_hda_codec_read(codec, 0x14, 0,
5729 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02005730 snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0,
5731 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
5732 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
5733 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Nicola Fagnanic54728d2007-07-19 23:28:52 +02005734}
5735
5736/* Processes unsolicited events. */
5737static void alc885_imac24_unsol_event(struct hda_codec *codec,
5738 unsigned int res)
5739{
5740 /* Headphone insertion or removal. */
5741 if ((res >> 26) == ALC880_HP_EVENT)
5742 alc885_imac24_automute(codec);
5743}
5744
Takashi Iwai87350ad2007-08-16 18:19:38 +02005745static void alc885_mbp3_automute(struct hda_codec *codec)
5746{
5747 unsigned int present;
5748
5749 present = snd_hda_codec_read(codec, 0x15, 0,
5750 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
5751 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
5752 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
5753 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
5754 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
5755
5756}
5757static void alc885_mbp3_unsol_event(struct hda_codec *codec,
5758 unsigned int res)
5759{
5760 /* Headphone insertion or removal. */
5761 if ((res >> 26) == ALC880_HP_EVENT)
5762 alc885_mbp3_automute(codec);
5763}
5764
5765
Kailang Yang272a5272007-05-14 11:00:38 +02005766static struct hda_verb alc882_targa_verbs[] = {
5767 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5768 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5769
5770 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5771 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5772
5773 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
5774 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
5775 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
5776
5777 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
5778 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
5779 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
5780 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
5781 { } /* end */
5782};
5783
5784/* toggle speaker-output according to the hp-jack state */
5785static void alc882_targa_automute(struct hda_codec *codec)
5786{
5787 unsigned int present;
5788
5789 present = snd_hda_codec_read(codec, 0x14, 0,
5790 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02005791 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
5792 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005793 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
5794 present ? 1 : 3);
Kailang Yang272a5272007-05-14 11:00:38 +02005795}
5796
5797static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
5798{
5799 /* Looks like the unsol event is incompatible with the standard
5800 * definition. 4bit tag is placed at 26 bit!
5801 */
5802 if (((res >> 26) == ALC880_HP_EVENT)) {
5803 alc882_targa_automute(codec);
5804 }
5805}
5806
5807static struct hda_verb alc882_asus_a7j_verbs[] = {
5808 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5809 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5810
5811 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5812 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5813 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5814
5815 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
5816 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
5817 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
5818
5819 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
5820 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
5821 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
5822 { } /* end */
5823};
5824
Takashi Iwai914759b2007-09-06 14:52:04 +02005825static struct hda_verb alc882_asus_a7m_verbs[] = {
5826 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5827 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5828
5829 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5830 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5831 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5832
5833 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
5834 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
5835 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
5836
5837 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
5838 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
5839 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
5840 { } /* end */
5841};
5842
Tobin Davis9102cd12006-12-15 10:02:12 +01005843static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
5844{
5845 unsigned int gpiostate, gpiomask, gpiodir;
5846
5847 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
5848 AC_VERB_GET_GPIO_DATA, 0);
5849
5850 if (!muted)
5851 gpiostate |= (1 << pin);
5852 else
5853 gpiostate &= ~(1 << pin);
5854
5855 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
5856 AC_VERB_GET_GPIO_MASK, 0);
5857 gpiomask |= (1 << pin);
5858
5859 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
5860 AC_VERB_GET_GPIO_DIRECTION, 0);
5861 gpiodir |= (1 << pin);
5862
5863
5864 snd_hda_codec_write(codec, codec->afg, 0,
5865 AC_VERB_SET_GPIO_MASK, gpiomask);
5866 snd_hda_codec_write(codec, codec->afg, 0,
5867 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
5868
5869 msleep(1);
5870
5871 snd_hda_codec_write(codec, codec->afg, 0,
5872 AC_VERB_SET_GPIO_DATA, gpiostate);
5873}
5874
Takashi Iwai7debbe52007-08-16 15:01:03 +02005875/* set up GPIO at initialization */
5876static void alc885_macpro_init_hook(struct hda_codec *codec)
5877{
5878 alc882_gpio_mute(codec, 0, 0);
5879 alc882_gpio_mute(codec, 1, 0);
5880}
5881
5882/* set up GPIO and update auto-muting at initialization */
5883static void alc885_imac24_init_hook(struct hda_codec *codec)
5884{
5885 alc885_macpro_init_hook(codec);
5886 alc885_imac24_automute(codec);
5887}
5888
Kailang Yangdf694da2005-12-05 19:42:22 +01005889/*
5890 * generic initialization of ADC, input mixers and output mixers
5891 */
5892static struct hda_verb alc882_auto_init_verbs[] = {
5893 /*
5894 * Unmute ADC0-2 and set the default input to mic-in
5895 */
5896 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
5897 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5898 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
5899 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5900 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
5901 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5902
Takashi Iwaicb53c622007-08-10 17:21:45 +02005903 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01005904 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005905 * Note: PASD motherboards uses the Line In 2 as the input for
5906 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01005907 */
5908 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005909 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5910 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5911 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5912 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5913 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01005914
5915 /*
5916 * Set up output mixers (0x0c - 0x0f)
5917 */
5918 /* set vol=0 to output mixers */
5919 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5920 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5921 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5922 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5923 /* set up input amps for analog loopback */
5924 /* Amp Indices: DAC = 0, mixer = 1 */
5925 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5926 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5927 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5928 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5929 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5930 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5931 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5932 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5933 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5934 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5935
5936 /* FIXME: use matrix-type input source selection */
5937 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
5938 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
5939 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5940 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
5941 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
5942 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
5943 /* Input mixer2 */
5944 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5945 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
5946 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
5947 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
5948 /* Input mixer3 */
5949 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5950 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
5951 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
5952 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
5953
5954 { }
5955};
5956
5957/* capture mixer elements */
5958static struct snd_kcontrol_new alc882_capture_alt_mixer[] = {
5959 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
5960 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
5961 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
5962 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
5963 {
5964 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5965 /* The multiple "Capture Source" controls confuse alsamixer
5966 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01005967 */
5968 /* .name = "Capture Source", */
5969 .name = "Input Source",
5970 .count = 2,
5971 .info = alc882_mux_enum_info,
5972 .get = alc882_mux_enum_get,
5973 .put = alc882_mux_enum_put,
5974 },
5975 { } /* end */
5976};
5977
5978static struct snd_kcontrol_new alc882_capture_mixer[] = {
5979 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
5980 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
5981 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
5982 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
5983 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
5984 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
5985 {
5986 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5987 /* The multiple "Capture Source" controls confuse alsamixer
5988 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01005989 */
5990 /* .name = "Capture Source", */
5991 .name = "Input Source",
5992 .count = 3,
5993 .info = alc882_mux_enum_info,
5994 .get = alc882_mux_enum_get,
5995 .put = alc882_mux_enum_put,
5996 },
5997 { } /* end */
5998};
5999
Takashi Iwaicb53c622007-08-10 17:21:45 +02006000#ifdef CONFIG_SND_HDA_POWER_SAVE
6001#define alc882_loopbacks alc880_loopbacks
6002#endif
6003
Kailang Yangdf694da2005-12-05 19:42:22 +01006004/* pcm configuration: identiacal with ALC880 */
6005#define alc882_pcm_analog_playback alc880_pcm_analog_playback
6006#define alc882_pcm_analog_capture alc880_pcm_analog_capture
6007#define alc882_pcm_digital_playback alc880_pcm_digital_playback
6008#define alc882_pcm_digital_capture alc880_pcm_digital_capture
6009
6010/*
6011 * configuration and preset
6012 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006013static const char *alc882_models[ALC882_MODEL_LAST] = {
6014 [ALC882_3ST_DIG] = "3stack-dig",
6015 [ALC882_6ST_DIG] = "6stack-dig",
6016 [ALC882_ARIMA] = "arima",
Kailang Yangbdd148a2007-05-08 15:19:08 +02006017 [ALC882_W2JC] = "w2jc",
Takashi Iwai0438a002007-09-06 14:54:11 +02006018 [ALC882_TARGA] = "targa",
6019 [ALC882_ASUS_A7J] = "asus-a7j",
6020 [ALC882_ASUS_A7M] = "asus-a7m",
Tobin Davis9102cd12006-12-15 10:02:12 +01006021 [ALC885_MACPRO] = "macpro",
Takashi Iwai87350ad2007-08-16 18:19:38 +02006022 [ALC885_MBP3] = "mbp3",
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006023 [ALC885_IMAC24] = "imac24",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006024 [ALC882_AUTO] = "auto",
6025};
6026
6027static struct snd_pci_quirk alc882_cfg_tbl[] = {
6028 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
Kailang Yang272a5272007-05-14 11:00:38 +02006029 SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
Kailang Yangac8842a2007-09-20 12:51:39 +02006030 SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
Takashi Iwai914759b2007-09-06 14:52:04 +02006031 SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006032 SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
Claudio Matsuokac5d9f1c2007-07-19 23:18:32 +02006033 SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
Tobin Davis7b9470d2006-12-28 13:56:48 +01006034 SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006035 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
Jiang zhe44447042008-01-28 12:28:24 +01006036 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006037 SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
6038 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
6039 SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA),
Kailang Yangdf694da2005-12-05 19:42:22 +01006040 {}
6041};
6042
6043static struct alc_config_preset alc882_presets[] = {
6044 [ALC882_3ST_DIG] = {
6045 .mixers = { alc882_base_mixer },
6046 .init_verbs = { alc882_init_verbs },
6047 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6048 .dac_nids = alc882_dac_nids,
6049 .dig_out_nid = ALC882_DIGOUT_NID,
Kailang Yangdf694da2005-12-05 19:42:22 +01006050 .dig_in_nid = ALC882_DIGIN_NID,
6051 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6052 .channel_mode = alc882_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02006053 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01006054 .input_mux = &alc882_capture_source,
6055 },
6056 [ALC882_6ST_DIG] = {
6057 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
6058 .init_verbs = { alc882_init_verbs },
6059 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6060 .dac_nids = alc882_dac_nids,
6061 .dig_out_nid = ALC882_DIGOUT_NID,
Kailang Yangdf694da2005-12-05 19:42:22 +01006062 .dig_in_nid = ALC882_DIGIN_NID,
6063 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
6064 .channel_mode = alc882_sixstack_modes,
6065 .input_mux = &alc882_capture_source,
6066 },
Takashi Iwai4b146cb2006-07-28 14:42:36 +02006067 [ALC882_ARIMA] = {
6068 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
6069 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs },
6070 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6071 .dac_nids = alc882_dac_nids,
6072 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
6073 .channel_mode = alc882_sixstack_modes,
6074 .input_mux = &alc882_capture_source,
6075 },
Kailang Yangbdd148a2007-05-08 15:19:08 +02006076 [ALC882_W2JC] = {
6077 .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
6078 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
6079 alc880_gpio1_init_verbs },
6080 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6081 .dac_nids = alc882_dac_nids,
6082 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
6083 .channel_mode = alc880_threestack_modes,
6084 .need_dac_fix = 1,
6085 .input_mux = &alc882_capture_source,
6086 .dig_out_nid = ALC882_DIGOUT_NID,
6087 },
Takashi Iwai87350ad2007-08-16 18:19:38 +02006088 [ALC885_MBP3] = {
6089 .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
6090 .init_verbs = { alc885_mbp3_init_verbs,
6091 alc880_gpio1_init_verbs },
6092 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6093 .dac_nids = alc882_dac_nids,
6094 .channel_mode = alc885_mbp_6ch_modes,
6095 .num_channel_mode = ARRAY_SIZE(alc885_mbp_6ch_modes),
6096 .input_mux = &alc882_capture_source,
6097 .dig_out_nid = ALC882_DIGOUT_NID,
6098 .dig_in_nid = ALC882_DIGIN_NID,
6099 .unsol_event = alc885_mbp3_unsol_event,
6100 .init_hook = alc885_mbp3_automute,
6101 },
Tobin Davis9102cd12006-12-15 10:02:12 +01006102 [ALC885_MACPRO] = {
6103 .mixers = { alc882_macpro_mixer },
6104 .init_verbs = { alc882_macpro_init_verbs },
6105 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6106 .dac_nids = alc882_dac_nids,
6107 .dig_out_nid = ALC882_DIGOUT_NID,
6108 .dig_in_nid = ALC882_DIGIN_NID,
6109 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6110 .channel_mode = alc882_ch_modes,
6111 .input_mux = &alc882_capture_source,
Takashi Iwai7debbe52007-08-16 15:01:03 +02006112 .init_hook = alc885_macpro_init_hook,
Tobin Davis9102cd12006-12-15 10:02:12 +01006113 },
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006114 [ALC885_IMAC24] = {
6115 .mixers = { alc885_imac24_mixer },
6116 .init_verbs = { alc885_imac24_init_verbs },
6117 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6118 .dac_nids = alc882_dac_nids,
6119 .dig_out_nid = ALC882_DIGOUT_NID,
6120 .dig_in_nid = ALC882_DIGIN_NID,
6121 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6122 .channel_mode = alc882_ch_modes,
6123 .input_mux = &alc882_capture_source,
6124 .unsol_event = alc885_imac24_unsol_event,
Takashi Iwai7debbe52007-08-16 15:01:03 +02006125 .init_hook = alc885_imac24_init_hook,
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006126 },
Kailang Yang272a5272007-05-14 11:00:38 +02006127 [ALC882_TARGA] = {
6128 .mixers = { alc882_targa_mixer, alc882_chmode_mixer,
6129 alc882_capture_mixer },
6130 .init_verbs = { alc882_init_verbs, alc882_targa_verbs},
6131 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6132 .dac_nids = alc882_dac_nids,
6133 .dig_out_nid = ALC882_DIGOUT_NID,
6134 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
6135 .adc_nids = alc882_adc_nids,
Takashi Iwaie1406342008-02-11 18:32:32 +01006136 .capsrc_nids = alc882_capsrc_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02006137 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
6138 .channel_mode = alc882_3ST_6ch_modes,
6139 .need_dac_fix = 1,
6140 .input_mux = &alc882_capture_source,
6141 .unsol_event = alc882_targa_unsol_event,
6142 .init_hook = alc882_targa_automute,
6143 },
6144 [ALC882_ASUS_A7J] = {
6145 .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer,
6146 alc882_capture_mixer },
6147 .init_verbs = { alc882_init_verbs, alc882_asus_a7j_verbs},
6148 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6149 .dac_nids = alc882_dac_nids,
6150 .dig_out_nid = ALC882_DIGOUT_NID,
6151 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
6152 .adc_nids = alc882_adc_nids,
Takashi Iwaie1406342008-02-11 18:32:32 +01006153 .capsrc_nids = alc882_capsrc_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02006154 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
6155 .channel_mode = alc882_3ST_6ch_modes,
6156 .need_dac_fix = 1,
6157 .input_mux = &alc882_capture_source,
6158 },
Takashi Iwai914759b2007-09-06 14:52:04 +02006159 [ALC882_ASUS_A7M] = {
6160 .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
6161 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
6162 alc880_gpio1_init_verbs,
6163 alc882_asus_a7m_verbs },
6164 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6165 .dac_nids = alc882_dac_nids,
6166 .dig_out_nid = ALC882_DIGOUT_NID,
6167 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
6168 .channel_mode = alc880_threestack_modes,
6169 .need_dac_fix = 1,
6170 .input_mux = &alc882_capture_source,
6171 },
Kailang Yangdf694da2005-12-05 19:42:22 +01006172};
6173
6174
6175/*
Takashi Iwaif95474e2007-07-10 00:47:43 +02006176 * Pin config fixes
6177 */
6178enum {
6179 PINFIX_ABIT_AW9D_MAX
6180};
6181
6182static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
6183 { 0x15, 0x01080104 }, /* side */
6184 { 0x16, 0x01011012 }, /* rear */
6185 { 0x17, 0x01016011 }, /* clfe */
6186 { }
6187};
6188
6189static const struct alc_pincfg *alc882_pin_fixes[] = {
6190 [PINFIX_ABIT_AW9D_MAX] = alc882_abit_aw9d_pinfix,
6191};
6192
6193static struct snd_pci_quirk alc882_pinfix_tbl[] = {
6194 SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
6195 {}
6196};
6197
6198/*
Kailang Yangdf694da2005-12-05 19:42:22 +01006199 * BIOS auto configuration
6200 */
6201static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
6202 hda_nid_t nid, int pin_type,
6203 int dac_idx)
6204{
6205 /* set as output */
6206 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006207 int idx;
6208
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006209 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01006210 if (spec->multiout.dac_nids[dac_idx] == 0x25)
6211 idx = 4;
6212 else
6213 idx = spec->multiout.dac_nids[dac_idx] - 2;
Kailang Yangdf694da2005-12-05 19:42:22 +01006214 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
6215
6216}
6217
6218static void alc882_auto_init_multi_out(struct hda_codec *codec)
6219{
6220 struct alc_spec *spec = codec->spec;
6221 int i;
6222
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006223 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Kailang Yangdf694da2005-12-05 19:42:22 +01006224 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006225 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006226 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01006227 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006228 alc882_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006229 i);
Kailang Yangdf694da2005-12-05 19:42:22 +01006230 }
6231}
6232
6233static void alc882_auto_init_hp_out(struct hda_codec *codec)
6234{
6235 struct alc_spec *spec = codec->spec;
6236 hda_nid_t pin;
6237
Takashi Iwaieb06ed82006-09-20 17:10:27 +02006238 pin = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006239 if (pin) /* connect to front */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006240 /* use dac 0 */
6241 alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006242 pin = spec->autocfg.speaker_pins[0];
6243 if (pin)
6244 alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +01006245}
6246
6247#define alc882_is_input_pin(nid) alc880_is_input_pin(nid)
6248#define ALC882_PIN_CD_NID ALC880_PIN_CD_NID
6249
6250static void alc882_auto_init_analog_input(struct hda_codec *codec)
6251{
6252 struct alc_spec *spec = codec->spec;
6253 int i;
6254
6255 for (i = 0; i < AUTO_PIN_LAST; i++) {
6256 hda_nid_t nid = spec->autocfg.input_pins[i];
6257 if (alc882_is_input_pin(nid)) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006258 snd_hda_codec_write(codec, nid, 0,
6259 AC_VERB_SET_PIN_WIDGET_CONTROL,
6260 i <= AUTO_PIN_FRONT_MIC ?
6261 PIN_VREF80 : PIN_IN);
Kailang Yangdf694da2005-12-05 19:42:22 +01006262 if (nid != ALC882_PIN_CD_NID)
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006263 snd_hda_codec_write(codec, nid, 0,
6264 AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangdf694da2005-12-05 19:42:22 +01006265 AMP_OUT_MUTE);
6266 }
6267 }
6268}
6269
Takashi Iwai776e1842007-08-29 15:07:11 +02006270/* add mic boosts if needed */
6271static int alc_auto_add_mic_boost(struct hda_codec *codec)
6272{
6273 struct alc_spec *spec = codec->spec;
6274 int err;
6275 hda_nid_t nid;
6276
6277 nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
Takashi Iwaice22e032008-01-11 17:38:35 +01006278 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
Takashi Iwai776e1842007-08-29 15:07:11 +02006279 err = add_control(spec, ALC_CTL_WIDGET_VOL,
6280 "Mic Boost",
6281 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
6282 if (err < 0)
6283 return err;
6284 }
6285 nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
Takashi Iwaice22e032008-01-11 17:38:35 +01006286 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
Takashi Iwai776e1842007-08-29 15:07:11 +02006287 err = add_control(spec, ALC_CTL_WIDGET_VOL,
6288 "Front Mic Boost",
6289 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
6290 if (err < 0)
6291 return err;
6292 }
6293 return 0;
6294}
6295
Kailang Yangdf694da2005-12-05 19:42:22 +01006296/* almost identical with ALC880 parser... */
6297static int alc882_parse_auto_config(struct hda_codec *codec)
6298{
6299 struct alc_spec *spec = codec->spec;
6300 int err = alc880_parse_auto_config(codec);
6301
6302 if (err < 0)
6303 return err;
Takashi Iwai776e1842007-08-29 15:07:11 +02006304 else if (!err)
6305 return 0; /* no config found */
6306
6307 err = alc_auto_add_mic_boost(codec);
6308 if (err < 0)
6309 return err;
6310
6311 /* hack - override the init verbs */
6312 spec->init_verbs[0] = alc882_auto_init_verbs;
6313
6314 return 1; /* config found */
Kailang Yangdf694da2005-12-05 19:42:22 +01006315}
6316
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006317/* additional initialization for auto-configuration model */
6318static void alc882_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01006319{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006320 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006321 alc882_auto_init_multi_out(codec);
6322 alc882_auto_init_hp_out(codec);
6323 alc882_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006324 if (spec->unsol_event)
6325 alc_sku_automute(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01006326}
6327
Linus Torvalds1da177e2005-04-16 15:20:36 -07006328static int patch_alc882(struct hda_codec *codec)
6329{
6330 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006331 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006332
Takashi Iwaie560d8d2005-09-09 14:21:46 +02006333 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006334 if (spec == NULL)
6335 return -ENOMEM;
6336
Linus Torvalds1da177e2005-04-16 15:20:36 -07006337 codec->spec = spec;
6338
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006339 board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
6340 alc882_models,
6341 alc882_cfg_tbl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006342
Kailang Yangdf694da2005-12-05 19:42:22 +01006343 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
Tobin Davis081d17c2007-02-15 17:46:18 +01006344 /* Pick up systems that don't supply PCI SSID */
6345 switch (codec->subsystem_id) {
6346 case 0x106b0c00: /* Mac Pro */
6347 board_config = ALC885_MACPRO;
6348 break;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006349 case 0x106b1000: /* iMac 24 */
6350 board_config = ALC885_IMAC24;
6351 break;
Jiang zhe3d5fa2e2008-01-10 13:05:47 +01006352 case 0x106b00a1: /* Macbook */
Takashi Iwai87350ad2007-08-16 18:19:38 +02006353 case 0x106b2c00: /* Macbook Pro rev3 */
6354 board_config = ALC885_MBP3;
6355 break;
Tobin Davis081d17c2007-02-15 17:46:18 +01006356 default:
6357 printk(KERN_INFO "hda_codec: Unknown model for ALC882, "
6358 "trying auto-probe from BIOS...\n");
6359 board_config = ALC882_AUTO;
6360 }
Kailang Yangdf694da2005-12-05 19:42:22 +01006361 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006362
Takashi Iwaif95474e2007-07-10 00:47:43 +02006363 alc_fix_pincfg(codec, alc882_pinfix_tbl, alc882_pin_fixes);
6364
Kailang Yangdf694da2005-12-05 19:42:22 +01006365 if (board_config == ALC882_AUTO) {
6366 /* automatic parse from the BIOS config */
6367 err = alc882_parse_auto_config(codec);
6368 if (err < 0) {
6369 alc_free(codec);
6370 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006371 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006372 printk(KERN_INFO
6373 "hda_codec: Cannot set up configuration "
6374 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01006375 board_config = ALC882_3ST_DIG;
6376 }
6377 }
6378
6379 if (board_config != ALC882_AUTO)
6380 setup_preset(spec, &alc882_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006381
6382 spec->stream_name_analog = "ALC882 Analog";
Kailang Yangdf694da2005-12-05 19:42:22 +01006383 spec->stream_analog_playback = &alc882_pcm_analog_playback;
6384 spec->stream_analog_capture = &alc882_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01006385 /* FIXME: setup DAC5 */
6386 /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
6387 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006388
6389 spec->stream_name_digital = "ALC882 Digital";
Kailang Yangdf694da2005-12-05 19:42:22 +01006390 spec->stream_digital_playback = &alc882_pcm_digital_playback;
6391 spec->stream_digital_capture = &alc882_pcm_digital_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006392
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006393 if (!spec->adc_nids && spec->input_mux) {
Kailang Yangdf694da2005-12-05 19:42:22 +01006394 /* check whether NID 0x07 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +01006395 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006396 /* get type */
6397 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Kailang Yangdf694da2005-12-05 19:42:22 +01006398 if (wcap != AC_WID_AUD_IN) {
6399 spec->adc_nids = alc882_adc_nids_alt;
6400 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids_alt);
Takashi Iwaie1406342008-02-11 18:32:32 +01006401 spec->capsrc_nids = alc882_capsrc_nids_alt;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006402 spec->mixers[spec->num_mixers] =
6403 alc882_capture_alt_mixer;
Kailang Yangdf694da2005-12-05 19:42:22 +01006404 spec->num_mixers++;
6405 } else {
6406 spec->adc_nids = alc882_adc_nids;
6407 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids);
Takashi Iwaie1406342008-02-11 18:32:32 +01006408 spec->capsrc_nids = alc882_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +01006409 spec->mixers[spec->num_mixers] = alc882_capture_mixer;
6410 spec->num_mixers++;
6411 }
6412 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006413
Takashi Iwai2134ea42008-01-10 16:53:55 +01006414 spec->vmaster_nid = 0x0c;
6415
Linus Torvalds1da177e2005-04-16 15:20:36 -07006416 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01006417 if (board_config == ALC882_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006418 spec->init_hook = alc882_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02006419#ifdef CONFIG_SND_HDA_POWER_SAVE
6420 if (!spec->loopback.amplist)
6421 spec->loopback.amplist = alc882_loopbacks;
6422#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006423
6424 return 0;
6425}
6426
6427/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006428 * ALC883 support
6429 *
6430 * ALC883 is almost identical with ALC880 but has cleaner and more flexible
6431 * configuration. Each pin widget can choose any input DACs and a mixer.
6432 * Each ADC is connected from a mixer of all inputs. This makes possible
6433 * 6-channel independent captures.
6434 *
6435 * In addition, an independent DAC for the multi-playback (not used in this
6436 * driver yet).
6437 */
6438#define ALC883_DIGOUT_NID 0x06
6439#define ALC883_DIGIN_NID 0x0a
6440
6441static hda_nid_t alc883_dac_nids[4] = {
6442 /* front, rear, clfe, rear_surr */
6443 0x02, 0x04, 0x03, 0x05
6444};
6445
6446static hda_nid_t alc883_adc_nids[2] = {
6447 /* ADC1-2 */
6448 0x08, 0x09,
6449};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006450
Takashi Iwaie1406342008-02-11 18:32:32 +01006451static hda_nid_t alc883_capsrc_nids[2] = { 0x23, 0x22 };
6452
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006453/* input MUX */
6454/* FIXME: should be a matrix-type input source selection */
6455
6456static struct hda_input_mux alc883_capture_source = {
6457 .num_items = 4,
6458 .items = {
6459 { "Mic", 0x0 },
6460 { "Front Mic", 0x1 },
6461 { "Line", 0x2 },
6462 { "CD", 0x4 },
6463 },
6464};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006465
6466static struct hda_input_mux alc883_lenovo_101e_capture_source = {
6467 .num_items = 2,
6468 .items = {
6469 { "Mic", 0x1 },
6470 { "Line", 0x2 },
6471 },
6472};
6473
Kailang Yang272a5272007-05-14 11:00:38 +02006474static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
6475 .num_items = 4,
6476 .items = {
6477 { "Mic", 0x0 },
6478 { "iMic", 0x1 },
6479 { "Line", 0x2 },
6480 { "CD", 0x4 },
6481 },
6482};
6483
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006484#define alc883_mux_enum_info alc_mux_enum_info
6485#define alc883_mux_enum_get alc_mux_enum_get
Takashi Iwaie1406342008-02-11 18:32:32 +01006486/* ALC883 has the ALC882-type input selection */
6487#define alc883_mux_enum_put alc882_mux_enum_put
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006488
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006489/*
6490 * 2ch mode
6491 */
6492static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
6493 { 2, NULL }
6494};
6495
6496/*
6497 * 2ch mode
6498 */
6499static struct hda_verb alc883_3ST_ch2_init[] = {
6500 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6501 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6502 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
6503 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6504 { } /* end */
6505};
6506
6507/*
Tobin Davisb2011312007-09-17 12:45:11 +02006508 * 4ch mode
6509 */
6510static struct hda_verb alc883_3ST_ch4_init[] = {
6511 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6512 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6513 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6514 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6515 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6516 { } /* end */
6517};
6518
6519/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006520 * 6ch mode
6521 */
6522static struct hda_verb alc883_3ST_ch6_init[] = {
6523 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6524 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6525 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
6526 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6527 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6528 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6529 { } /* end */
6530};
6531
Tobin Davisb2011312007-09-17 12:45:11 +02006532static struct hda_channel_mode alc883_3ST_6ch_modes[3] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006533 { 2, alc883_3ST_ch2_init },
Tobin Davisb2011312007-09-17 12:45:11 +02006534 { 4, alc883_3ST_ch4_init },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006535 { 6, alc883_3ST_ch6_init },
6536};
6537
6538/*
6539 * 6ch mode
6540 */
6541static struct hda_verb alc883_sixstack_ch6_init[] = {
6542 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
6543 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6544 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6545 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6546 { } /* end */
6547};
6548
6549/*
6550 * 8ch mode
6551 */
6552static struct hda_verb alc883_sixstack_ch8_init[] = {
6553 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6554 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6555 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6556 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6557 { } /* end */
6558};
6559
6560static struct hda_channel_mode alc883_sixstack_modes[2] = {
6561 { 6, alc883_sixstack_ch6_init },
6562 { 8, alc883_sixstack_ch8_init },
6563};
6564
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01006565static struct hda_verb alc883_medion_eapd_verbs[] = {
6566 /* eanable EAPD on medion laptop */
6567 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
6568 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
6569 { }
6570};
6571
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006572/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
6573 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
6574 */
6575
6576static struct snd_kcontrol_new alc883_base_mixer[] = {
6577 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6578 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6579 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6580 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
6581 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6582 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
6583 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
6584 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
6585 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
6586 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
6587 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6588 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6589 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6590 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6591 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6592 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006593 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006594 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6595 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006596 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006597 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6598 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6599 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6600 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6601 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6602 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6603 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6604 {
6605 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6606 /* .name = "Capture Source", */
6607 .name = "Input Source",
6608 .count = 2,
6609 .info = alc883_mux_enum_info,
6610 .get = alc883_mux_enum_get,
6611 .put = alc883_mux_enum_put,
6612 },
6613 { } /* end */
6614};
6615
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01006616static struct snd_kcontrol_new alc883_mitac_mixer[] = {
6617 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6618 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6619 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6620 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
6621 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
6622 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
6623 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
6624 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6625 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6626 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6627 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6628 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
6629 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6630 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6631 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6632 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6633 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6634 {
6635 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6636 /* .name = "Capture Source", */
6637 .name = "Input Source",
6638 .count = 2,
6639 .info = alc883_mux_enum_info,
6640 .get = alc883_mux_enum_get,
6641 .put = alc883_mux_enum_put,
6642 },
6643 { } /* end */
6644};
6645
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006646static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
6647 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6648 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6649 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6650 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6651 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6652 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6653 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6654 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006655 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006656 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6657 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006658 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006659 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6660 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6661 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6662 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6663 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6664 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6665 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6666 {
6667 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6668 /* .name = "Capture Source", */
6669 .name = "Input Source",
6670 .count = 2,
6671 .info = alc883_mux_enum_info,
6672 .get = alc883_mux_enum_get,
6673 .put = alc883_mux_enum_put,
6674 },
6675 { } /* end */
6676};
6677
6678static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
6679 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6680 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6681 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6682 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
6683 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6684 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
6685 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
6686 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
6687 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6688 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6689 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6690 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6691 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6692 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006693 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006694 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6695 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006696 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006697 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6698 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6699 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6700 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6701 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6702 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6703 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6704 {
6705 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6706 /* .name = "Capture Source", */
6707 .name = "Input Source",
6708 .count = 2,
6709 .info = alc883_mux_enum_info,
6710 .get = alc883_mux_enum_get,
6711 .put = alc883_mux_enum_put,
6712 },
6713 { } /* end */
6714};
6715
Takashi Iwaid1d985f2006-11-23 19:27:12 +01006716static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
Tobin Davisc07584c2006-10-13 12:32:16 +02006717 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6718 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
6719 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6720 HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
6721 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6722 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
6723 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT),
6724 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
6725 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6726 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6727 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6728 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6729 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6730 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006731 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02006732 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6733 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006734 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02006735 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6736 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6737 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6738 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6739 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6740
6741 {
6742 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6743 /* .name = "Capture Source", */
6744 .name = "Input Source",
6745 .count = 1,
6746 .info = alc883_mux_enum_info,
6747 .get = alc883_mux_enum_get,
6748 .put = alc883_mux_enum_put,
6749 },
6750 { } /* end */
6751};
6752
Kailang Yangccc656c2006-10-17 12:32:26 +02006753static struct snd_kcontrol_new alc883_tagra_mixer[] = {
6754 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6755 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
6756 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6757 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6758 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
6759 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6760 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
6761 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
6762 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
6763 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6764 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6765 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6766 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6767 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006768 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02006769 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6770 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6771 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6772 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6773 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6774 {
6775 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6776 /* .name = "Capture Source", */
6777 .name = "Input Source",
6778 .count = 2,
6779 .info = alc883_mux_enum_info,
6780 .get = alc883_mux_enum_get,
6781 .put = alc883_mux_enum_put,
6782 },
6783 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006784};
Kailang Yangccc656c2006-10-17 12:32:26 +02006785
6786static struct snd_kcontrol_new alc883_tagra_2ch_mixer[] = {
6787 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6788 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
6789 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6790 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6791 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6792 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006793 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02006794 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6795 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6796 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6797 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6798 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6799 {
6800 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6801 /* .name = "Capture Source", */
6802 .name = "Input Source",
6803 .count = 2,
6804 .info = alc883_mux_enum_info,
6805 .get = alc883_mux_enum_get,
6806 .put = alc883_mux_enum_put,
6807 },
6808 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006809};
Kailang Yangccc656c2006-10-17 12:32:26 +02006810
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006811static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
6812 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6813 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01006814 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6815 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006816 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6817 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6818 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6819 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6820 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6821 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6822 {
6823 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6824 /* .name = "Capture Source", */
6825 .name = "Input Source",
6826 .count = 1,
6827 .info = alc883_mux_enum_info,
6828 .get = alc883_mux_enum_get,
6829 .put = alc883_mux_enum_put,
6830 },
6831 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006832};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006833
Kailang Yang272a5272007-05-14 11:00:38 +02006834static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
6835 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6836 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
6837 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
6838 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6839 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6840 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6841 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6842 HDA_CODEC_VOLUME("iMic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6843 HDA_CODEC_MUTE("iMic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6844 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6845 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6846 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6847 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6848 {
6849 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6850 /* .name = "Capture Source", */
6851 .name = "Input Source",
6852 .count = 2,
6853 .info = alc883_mux_enum_info,
6854 .get = alc883_mux_enum_get,
6855 .put = alc883_mux_enum_put,
6856 },
6857 { } /* end */
6858};
6859
6860static struct snd_kcontrol_new alc883_medion_md2_mixer[] = {
6861 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6862 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
6863 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
6864 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6865 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6866 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6867 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6868 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6869 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6870 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6871 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6872 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6873 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6874 {
6875 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6876 /* .name = "Capture Source", */
6877 .name = "Input Source",
6878 .count = 2,
6879 .info = alc883_mux_enum_info,
6880 .get = alc883_mux_enum_get,
6881 .put = alc883_mux_enum_put,
6882 },
6883 { } /* end */
6884};
6885
Claudio Matsuoka4723c022007-07-13 14:36:19 +02006886static struct snd_kcontrol_new alc888_6st_hp_mixer[] = {
Claudio Matsuokacd1e3b42007-07-06 12:10:01 +02006887 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6888 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6889 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
6890 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
6891 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
6892 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
6893 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
6894 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
6895 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
6896 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
6897 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6898 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6899 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6900 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6901 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6902 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6903 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6904 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6905 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6906 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
6907 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6908 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6909 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6910 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6911 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6912 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6913 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6914 {
6915 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6916 /* .name = "Capture Source", */
6917 .name = "Input Source",
6918 .count = 2,
6919 .info = alc883_mux_enum_info,
6920 .get = alc883_mux_enum_get,
6921 .put = alc883_mux_enum_put,
6922 },
6923 { } /* end */
6924};
6925
Claudio Matsuoka4723c022007-07-13 14:36:19 +02006926static struct snd_kcontrol_new alc888_3st_hp_mixer[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02006927 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6928 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6929 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
6930 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
6931 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
6932 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
6933 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
6934 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
6935 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6936 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6937 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6938 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6939 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6940 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6941 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6942 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6943 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6944 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
6945 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6946 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6947 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6948 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6949 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6950 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6951 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6952 {
6953 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6954 /* .name = "Capture Source", */
6955 .name = "Input Source",
6956 .count = 2,
6957 .info = alc883_mux_enum_info,
6958 .get = alc883_mux_enum_get,
6959 .put = alc883_mux_enum_put,
6960 },
6961 { } /* end */
6962};
6963
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01006964static struct snd_kcontrol_new alc888_6st_dell_mixer[] = {
6965 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6966 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6967 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
6968 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
6969 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
6970 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
6971 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
6972 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
6973 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
6974 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
6975 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6976 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6977 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6978 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6979 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6980 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6981 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6982 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6983 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6984 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
6985 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6986 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6987 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6988 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6989 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6990 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6991 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6992 {
6993 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6994 /* .name = "Capture Source", */
6995 .name = "Input Source",
6996 .count = 2,
6997 .info = alc883_mux_enum_info,
6998 .get = alc883_mux_enum_get,
6999 .put = alc883_mux_enum_put,
7000 },
7001 { } /* end */
7002};
7003
Tobin Davis2880a862007-08-07 11:50:26 +02007004static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02007005 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7006 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007007 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007008 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7009 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02007010 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7011 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7012 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007013 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7014 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7015 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7016 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7017 {
7018 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7019 /* .name = "Capture Source", */
7020 .name = "Input Source",
7021 .count = 2,
7022 .info = alc883_mux_enum_info,
7023 .get = alc883_mux_enum_get,
7024 .put = alc883_mux_enum_put,
7025 },
7026 { } /* end */
Kailang Yangd1a991a2007-08-15 16:21:59 +02007027};
Tobin Davis2880a862007-08-07 11:50:26 +02007028
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007029static struct snd_kcontrol_new alc883_chmode_mixer[] = {
7030 {
7031 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7032 .name = "Channel Mode",
7033 .info = alc_ch_mode_info,
7034 .get = alc_ch_mode_get,
7035 .put = alc_ch_mode_put,
7036 },
7037 { } /* end */
7038};
7039
7040static struct hda_verb alc883_init_verbs[] = {
7041 /* ADC1: mute amp left and right */
7042 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7043 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7044 /* ADC2: mute amp left and right */
7045 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7046 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
7047 /* Front mixer: unmute input/output amp left and right (volume = 0) */
7048 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7049 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7050 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7051 /* Rear mixer */
7052 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7053 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7054 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7055 /* CLFE mixer */
7056 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7057 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7058 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7059 /* Side mixer */
7060 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7061 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7062 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7063
Takashi Iwaicb53c622007-08-10 17:21:45 +02007064 /* mute analog input loopbacks */
7065 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7066 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7067 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7068 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7069 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007070
7071 /* Front Pin: output 0 (0x0c) */
7072 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7073 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7074 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7075 /* Rear Pin: output 1 (0x0d) */
7076 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7077 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7078 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
7079 /* CLFE Pin: output 2 (0x0e) */
7080 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7081 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7082 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
7083 /* Side Pin: output 3 (0x0f) */
7084 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7085 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7086 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
7087 /* Mic (rear) pin: input vref at 80% */
7088 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7089 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7090 /* Front Mic pin: input vref at 80% */
7091 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7092 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7093 /* Line In pin: input */
7094 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7095 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7096 /* Line-2 In: Headphone output (output 0 - 0x0c) */
7097 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7098 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7099 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
7100 /* CD pin widget for input */
7101 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7102
7103 /* FIXME: use matrix-type input source selection */
7104 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
7105 /* Input mixer2 */
7106 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7107 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7108 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
7109 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
7110 /* Input mixer3 */
7111 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7112 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7113 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
7114 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
7115 { }
7116};
7117
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007118/* toggle speaker-output according to the hp-jack state */
7119static void alc883_mitac_hp_automute(struct hda_codec *codec)
7120{
7121 unsigned int present;
7122
7123 present = snd_hda_codec_read(codec, 0x15, 0,
7124 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7125 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7126 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7127 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
7128 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7129}
7130
7131/* auto-toggle front mic */
7132/*
7133static void alc883_mitac_mic_automute(struct hda_codec *codec)
7134{
7135 unsigned int present;
7136 unsigned char bits;
7137
7138 present = snd_hda_codec_read(codec, 0x18, 0,
7139 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7140 bits = present ? HDA_AMP_MUTE : 0;
7141 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
7142}
7143*/
7144
7145static void alc883_mitac_automute(struct hda_codec *codec)
7146{
7147 alc883_mitac_hp_automute(codec);
7148 /* alc883_mitac_mic_automute(codec); */
7149}
7150
7151static void alc883_mitac_unsol_event(struct hda_codec *codec,
7152 unsigned int res)
7153{
7154 switch (res >> 26) {
7155 case ALC880_HP_EVENT:
7156 alc883_mitac_hp_automute(codec);
7157 break;
7158 case ALC880_MIC_EVENT:
7159 /* alc883_mitac_mic_automute(codec); */
7160 break;
7161 }
7162}
7163
7164static struct hda_verb alc883_mitac_verbs[] = {
7165 /* HP */
7166 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7167 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7168 /* Subwoofer */
7169 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
7170 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7171
7172 /* enable unsolicited event */
7173 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7174 /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
7175
7176 { } /* end */
7177};
7178
Kailang Yangccc656c2006-10-17 12:32:26 +02007179static struct hda_verb alc883_tagra_verbs[] = {
7180 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7181 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7182
7183 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7184 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7185
7186 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
7187 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
7188 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
7189
7190 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007191 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
7192 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
7193 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
Kailang Yangccc656c2006-10-17 12:32:26 +02007194
7195 { } /* end */
7196};
7197
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007198static struct hda_verb alc883_lenovo_101e_verbs[] = {
7199 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7200 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
7201 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
7202 { } /* end */
7203};
7204
Kailang Yang272a5272007-05-14 11:00:38 +02007205static struct hda_verb alc883_lenovo_nb0763_verbs[] = {
7206 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7207 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7208 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7209 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7210 { } /* end */
7211};
7212
7213static struct hda_verb alc888_lenovo_ms7195_verbs[] = {
7214 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7215 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7216 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7217 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN},
7218 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7219 { } /* end */
7220};
7221
Kailang Yang189609a2007-08-20 11:31:23 +02007222static struct hda_verb alc883_haier_w66_verbs[] = {
7223 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7224 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7225
7226 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7227
7228 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
7229 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7230 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7231 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7232 { } /* end */
7233};
7234
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007235static struct hda_verb alc888_6st_hp_verbs[] = {
Claudio Matsuokacd1e3b42007-07-06 12:10:01 +02007236 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
7237 {0x15, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Rear : output 2 (0x0e) */
7238 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* CLFE : output 1 (0x0d) */
7239 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, /* Side : output 3 (0x0f) */
7240 { }
7241};
7242
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007243static struct hda_verb alc888_3st_hp_verbs[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007244 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
7245 {0x18, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */
7246 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */
7247 { }
7248};
7249
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007250static struct hda_verb alc888_6st_dell_verbs[] = {
7251 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
7252 {0x15, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Rear : output 1 (0x0e) */
7253 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* CLFE : output 2 (0x0d) */
7254 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, /* Side : output 3 (0x0f) */
7255 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7256 { }
7257};
7258
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007259static struct hda_verb alc888_3st_hp_2ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007260 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7261 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7262 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7263 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7264 { }
7265};
7266
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007267static struct hda_verb alc888_3st_hp_6ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007268 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7269 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7270 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7271 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7272 { }
7273};
7274
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007275static struct hda_channel_mode alc888_3st_hp_modes[2] = {
7276 { 2, alc888_3st_hp_2ch_init },
7277 { 6, alc888_3st_hp_6ch_init },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007278};
7279
Kailang Yang272a5272007-05-14 11:00:38 +02007280/* toggle front-jack and RCA according to the hp-jack state */
7281static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
7282{
7283 unsigned int present;
7284
7285 present = snd_hda_codec_read(codec, 0x1b, 0,
7286 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007287 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7288 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7289 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7290 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007291}
7292
7293/* toggle RCA according to the front-jack state */
7294static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec)
7295{
7296 unsigned int present;
7297
7298 present = snd_hda_codec_read(codec, 0x14, 0,
7299 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007300 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7301 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007302}
Takashi Iwai47fd8302007-08-10 17:11:07 +02007303
Kailang Yang272a5272007-05-14 11:00:38 +02007304static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec,
7305 unsigned int res)
7306{
7307 if ((res >> 26) == ALC880_HP_EVENT)
7308 alc888_lenovo_ms7195_front_automute(codec);
7309 if ((res >> 26) == ALC880_FRONT_EVENT)
7310 alc888_lenovo_ms7195_rca_automute(codec);
7311}
7312
7313static struct hda_verb alc883_medion_md2_verbs[] = {
7314 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7315 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7316
7317 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7318
7319 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7320 { } /* end */
7321};
7322
7323/* toggle speaker-output according to the hp-jack state */
7324static void alc883_medion_md2_automute(struct hda_codec *codec)
7325{
7326 unsigned int present;
7327
7328 present = snd_hda_codec_read(codec, 0x14, 0,
7329 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007330 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7331 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007332}
7333
7334static void alc883_medion_md2_unsol_event(struct hda_codec *codec,
7335 unsigned int res)
7336{
7337 if ((res >> 26) == ALC880_HP_EVENT)
7338 alc883_medion_md2_automute(codec);
7339}
7340
Kailang Yangccc656c2006-10-17 12:32:26 +02007341/* toggle speaker-output according to the hp-jack state */
7342static void alc883_tagra_automute(struct hda_codec *codec)
7343{
7344 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007345 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02007346
7347 present = snd_hda_codec_read(codec, 0x14, 0,
7348 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007349 bits = present ? HDA_AMP_MUTE : 0;
7350 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
7351 HDA_AMP_MUTE, bits);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02007352 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
7353 present ? 1 : 3);
Kailang Yangccc656c2006-10-17 12:32:26 +02007354}
7355
7356static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res)
7357{
7358 if ((res >> 26) == ALC880_HP_EVENT)
7359 alc883_tagra_automute(codec);
7360}
7361
Kailang Yang189609a2007-08-20 11:31:23 +02007362static void alc883_haier_w66_automute(struct hda_codec *codec)
7363{
7364 unsigned int present;
7365 unsigned char bits;
7366
7367 present = snd_hda_codec_read(codec, 0x1b, 0,
7368 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7369 bits = present ? 0x80 : 0;
7370 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7371 0x80, bits);
7372}
7373
7374static void alc883_haier_w66_unsol_event(struct hda_codec *codec,
7375 unsigned int res)
7376{
7377 if ((res >> 26) == ALC880_HP_EVENT)
7378 alc883_haier_w66_automute(codec);
7379}
7380
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007381static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
7382{
7383 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007384 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007385
7386 present = snd_hda_codec_read(codec, 0x14, 0,
7387 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007388 bits = present ? HDA_AMP_MUTE : 0;
7389 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7390 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007391}
7392
7393static void alc883_lenovo_101e_all_automute(struct hda_codec *codec)
7394{
7395 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007396 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007397
7398 present = snd_hda_codec_read(codec, 0x1b, 0,
7399 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007400 bits = present ? HDA_AMP_MUTE : 0;
7401 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7402 HDA_AMP_MUTE, bits);
7403 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7404 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007405}
7406
7407static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec,
7408 unsigned int res)
7409{
7410 if ((res >> 26) == ALC880_HP_EVENT)
7411 alc883_lenovo_101e_all_automute(codec);
7412 if ((res >> 26) == ALC880_FRONT_EVENT)
7413 alc883_lenovo_101e_ispeaker_automute(codec);
7414}
7415
Takashi Iwai676a9b52007-08-16 15:23:35 +02007416/* toggle speaker-output according to the hp-jack state */
7417static void alc883_acer_aspire_automute(struct hda_codec *codec)
7418{
7419 unsigned int present;
7420
7421 present = snd_hda_codec_read(codec, 0x14, 0,
7422 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7423 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7424 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7425 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
7426 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7427}
7428
7429static void alc883_acer_aspire_unsol_event(struct hda_codec *codec,
7430 unsigned int res)
7431{
7432 if ((res >> 26) == ALC880_HP_EVENT)
7433 alc883_acer_aspire_automute(codec);
7434}
7435
Kailang Yangd1a991a2007-08-15 16:21:59 +02007436static struct hda_verb alc883_acer_eapd_verbs[] = {
7437 /* HP Pin: output 0 (0x0c) */
7438 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7439 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7440 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7441 /* Front Pin: output 0 (0x0c) */
Takashi Iwai676a9b52007-08-16 15:23:35 +02007442 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7443 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangd1a991a2007-08-15 16:21:59 +02007444 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangd1a991a2007-08-15 16:21:59 +02007445 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
7446 /* eanable EAPD on medion laptop */
7447 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
7448 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
Takashi Iwai676a9b52007-08-16 15:23:35 +02007449 /* enable unsolicited event */
7450 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangd1a991a2007-08-15 16:21:59 +02007451 { }
7452};
7453
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007454static void alc888_6st_dell_front_automute(struct hda_codec *codec)
7455{
7456 unsigned int present;
7457
7458 present = snd_hda_codec_read(codec, 0x1b, 0,
7459 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7460 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7461 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7462 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7463 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7464 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
7465 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7466 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
7467 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7468}
7469
7470static void alc888_6st_dell_unsol_event(struct hda_codec *codec,
7471 unsigned int res)
7472{
7473 switch (res >> 26) {
7474 case ALC880_HP_EVENT:
7475 printk("hp_event\n");
7476 alc888_6st_dell_front_automute(codec);
7477 break;
7478 }
7479}
7480
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007481/*
7482 * generic initialization of ADC, input mixers and output mixers
7483 */
7484static struct hda_verb alc883_auto_init_verbs[] = {
7485 /*
7486 * Unmute ADC0-2 and set the default input to mic-in
7487 */
7488 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7489 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7490 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
7491 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7492
Takashi Iwaicb53c622007-08-10 17:21:45 +02007493 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007494 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007495 * Note: PASD motherboards uses the Line In 2 as the input for
7496 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007497 */
7498 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02007499 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7500 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7501 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7502 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7503 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007504
7505 /*
7506 * Set up output mixers (0x0c - 0x0f)
7507 */
7508 /* set vol=0 to output mixers */
7509 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7510 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7511 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7512 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7513 /* set up input amps for analog loopback */
7514 /* Amp Indices: DAC = 0, mixer = 1 */
7515 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7516 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7517 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7518 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7519 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7520 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7521 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7522 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7523 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7524 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7525
7526 /* FIXME: use matrix-type input source selection */
7527 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
7528 /* Input mixer1 */
7529 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7530 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7531 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007532 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007533 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
7534 /* Input mixer2 */
7535 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7536 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7537 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007538 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
Andy Shevchenkoe3cde642007-12-03 16:50:58 +01007539 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007540
7541 { }
7542};
7543
7544/* capture mixer elements */
7545static struct snd_kcontrol_new alc883_capture_mixer[] = {
7546 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7547 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7548 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7549 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7550 {
7551 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7552 /* The multiple "Capture Source" controls confuse alsamixer
7553 * So call somewhat different..
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007554 */
7555 /* .name = "Capture Source", */
7556 .name = "Input Source",
7557 .count = 2,
7558 .info = alc882_mux_enum_info,
7559 .get = alc882_mux_enum_get,
7560 .put = alc882_mux_enum_put,
7561 },
7562 { } /* end */
7563};
7564
Takashi Iwaicb53c622007-08-10 17:21:45 +02007565#ifdef CONFIG_SND_HDA_POWER_SAVE
7566#define alc883_loopbacks alc880_loopbacks
7567#endif
7568
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007569/* pcm configuration: identiacal with ALC880 */
7570#define alc883_pcm_analog_playback alc880_pcm_analog_playback
7571#define alc883_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +01007572#define alc883_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007573#define alc883_pcm_digital_playback alc880_pcm_digital_playback
7574#define alc883_pcm_digital_capture alc880_pcm_digital_capture
7575
7576/*
7577 * configuration and preset
7578 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007579static const char *alc883_models[ALC883_MODEL_LAST] = {
7580 [ALC883_3ST_2ch_DIG] = "3stack-dig",
7581 [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
7582 [ALC883_3ST_6ch] = "3stack-6ch",
7583 [ALC883_6ST_DIG] = "6stack-dig",
7584 [ALC883_TARGA_DIG] = "targa-dig",
7585 [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007586 [ALC883_ACER] = "acer",
Tobin Davis2880a862007-08-07 11:50:26 +02007587 [ALC883_ACER_ASPIRE] = "acer-aspire",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007588 [ALC883_MEDION] = "medion",
Kailang Yang272a5272007-05-14 11:00:38 +02007589 [ALC883_MEDION_MD2] = "medion-md2",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007590 [ALC883_LAPTOP_EAPD] = "laptop-eapd",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007591 [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
Kailang Yang272a5272007-05-14 11:00:38 +02007592 [ALC883_LENOVO_NB0763] = "lenovo-nb0763",
7593 [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
Kailang Yang189609a2007-08-20 11:31:23 +02007594 [ALC883_HAIER_W66] = "haier-w66",
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007595 [ALC888_6ST_HP] = "6stack-hp",
7596 [ALC888_3ST_HP] = "3stack-hp",
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007597 [ALC888_6ST_DELL] = "6stack-dell",
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007598 [ALC883_MITAC] = "mitac",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007599 [ALC883_AUTO] = "auto",
7600};
7601
7602static struct snd_pci_quirk alc883_cfg_tbl[] = {
7603 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007604 SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
7605 SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
7606 SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
7607 SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), /* default Acer */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007608 SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
Tobin Davisfebe3372007-06-12 11:27:46 +02007609 SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007610 SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
7611 SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
7612 SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC888_6ST_HP),
7613 SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007614 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007615 SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
7616 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
7617 SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
Tobin Davis57b14f22007-04-18 23:05:36 +02007618 SND_PCI_QUIRK(0x1458, 0xa002, "MSI", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007619 SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
7620 SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
7621 SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
7622 SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
7623 SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
7624 SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
7625 SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
7626 SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
7627 SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
7628 SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
7629 SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
7630 SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
7631 SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007632 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
7633 SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
Tobin Davis799f88a2007-05-29 14:29:08 +02007634 SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
Leonard Norrgard2a296cb2007-01-08 11:28:22 +01007635 SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
Tobin Davis2dcd5222007-07-10 17:04:57 +02007636 SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007637 SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007638 SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
7639 SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD),
Daniel T Chene60623b2007-05-29 03:41:55 -04007640 SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007641 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
Kailang Yang272a5272007-05-14 11:00:38 +02007642 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
Kailang Yang272a5272007-05-14 11:00:38 +02007643 SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007644 SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
7645 SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Kailang Yang272a5272007-05-14 11:00:38 +02007646 SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
Andrew Paprocki0b167bf2008-02-03 10:15:44 +01007647 SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
Kailang Yang189609a2007-08-20 11:31:23 +02007648 SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007649 SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007650 {}
7651};
7652
7653static struct alc_config_preset alc883_presets[] = {
7654 [ALC883_3ST_2ch_DIG] = {
7655 .mixers = { alc883_3ST_2ch_mixer },
7656 .init_verbs = { alc883_init_verbs },
7657 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7658 .dac_nids = alc883_dac_nids,
7659 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007660 .dig_in_nid = ALC883_DIGIN_NID,
7661 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7662 .channel_mode = alc883_3ST_2ch_modes,
7663 .input_mux = &alc883_capture_source,
7664 },
7665 [ALC883_3ST_6ch_DIG] = {
7666 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
7667 .init_verbs = { alc883_init_verbs },
7668 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7669 .dac_nids = alc883_dac_nids,
7670 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007671 .dig_in_nid = ALC883_DIGIN_NID,
7672 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
7673 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02007674 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007675 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007676 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007677 [ALC883_3ST_6ch] = {
7678 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
7679 .init_verbs = { alc883_init_verbs },
7680 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7681 .dac_nids = alc883_dac_nids,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007682 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
7683 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02007684 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007685 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007686 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007687 [ALC883_6ST_DIG] = {
7688 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
7689 .init_verbs = { alc883_init_verbs },
7690 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7691 .dac_nids = alc883_dac_nids,
7692 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007693 .dig_in_nid = ALC883_DIGIN_NID,
7694 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
7695 .channel_mode = alc883_sixstack_modes,
7696 .input_mux = &alc883_capture_source,
7697 },
Kailang Yangccc656c2006-10-17 12:32:26 +02007698 [ALC883_TARGA_DIG] = {
7699 .mixers = { alc883_tagra_mixer, alc883_chmode_mixer },
7700 .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
7701 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7702 .dac_nids = alc883_dac_nids,
7703 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02007704 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
7705 .channel_mode = alc883_3ST_6ch_modes,
7706 .need_dac_fix = 1,
7707 .input_mux = &alc883_capture_source,
7708 .unsol_event = alc883_tagra_unsol_event,
7709 .init_hook = alc883_tagra_automute,
7710 },
7711 [ALC883_TARGA_2ch_DIG] = {
7712 .mixers = { alc883_tagra_2ch_mixer},
7713 .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
7714 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7715 .dac_nids = alc883_dac_nids,
7716 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02007717 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7718 .channel_mode = alc883_3ST_2ch_modes,
7719 .input_mux = &alc883_capture_source,
7720 .unsol_event = alc883_tagra_unsol_event,
7721 .init_hook = alc883_tagra_automute,
7722 },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02007723 [ALC883_ACER] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02007724 .mixers = { alc883_base_mixer },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02007725 /* On TravelMate laptops, GPIO 0 enables the internal speaker
7726 * and the headphone jack. Turn this on and rely on the
7727 * standard mute methods whenever the user wants to turn
7728 * these outputs off.
7729 */
7730 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
7731 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7732 .dac_nids = alc883_dac_nids,
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02007733 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7734 .channel_mode = alc883_3ST_2ch_modes,
7735 .input_mux = &alc883_capture_source,
7736 },
Tobin Davis2880a862007-08-07 11:50:26 +02007737 [ALC883_ACER_ASPIRE] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02007738 .mixers = { alc883_acer_aspire_mixer },
Kailang Yangd1a991a2007-08-15 16:21:59 +02007739 .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs },
Tobin Davis2880a862007-08-07 11:50:26 +02007740 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7741 .dac_nids = alc883_dac_nids,
7742 .dig_out_nid = ALC883_DIGOUT_NID,
Tobin Davis2880a862007-08-07 11:50:26 +02007743 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7744 .channel_mode = alc883_3ST_2ch_modes,
7745 .input_mux = &alc883_capture_source,
Takashi Iwai676a9b52007-08-16 15:23:35 +02007746 .unsol_event = alc883_acer_aspire_unsol_event,
7747 .init_hook = alc883_acer_aspire_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +02007748 },
Tobin Davisc07584c2006-10-13 12:32:16 +02007749 [ALC883_MEDION] = {
7750 .mixers = { alc883_fivestack_mixer,
7751 alc883_chmode_mixer },
7752 .init_verbs = { alc883_init_verbs,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007753 alc883_medion_eapd_verbs },
Tobin Davisc07584c2006-10-13 12:32:16 +02007754 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7755 .dac_nids = alc883_dac_nids,
Tobin Davisc07584c2006-10-13 12:32:16 +02007756 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
7757 .channel_mode = alc883_sixstack_modes,
7758 .input_mux = &alc883_capture_source,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007759 },
Kailang Yang272a5272007-05-14 11:00:38 +02007760 [ALC883_MEDION_MD2] = {
7761 .mixers = { alc883_medion_md2_mixer},
7762 .init_verbs = { alc883_init_verbs, alc883_medion_md2_verbs},
7763 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7764 .dac_nids = alc883_dac_nids,
7765 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +02007766 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7767 .channel_mode = alc883_3ST_2ch_modes,
7768 .input_mux = &alc883_capture_source,
7769 .unsol_event = alc883_medion_md2_unsol_event,
7770 .init_hook = alc883_medion_md2_automute,
7771 },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007772 [ALC883_LAPTOP_EAPD] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02007773 .mixers = { alc883_base_mixer },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007774 .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
7775 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7776 .dac_nids = alc883_dac_nids,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007777 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7778 .channel_mode = alc883_3ST_2ch_modes,
7779 .input_mux = &alc883_capture_source,
7780 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007781 [ALC883_LENOVO_101E_2ch] = {
7782 .mixers = { alc883_lenovo_101e_2ch_mixer},
7783 .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
7784 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7785 .dac_nids = alc883_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007786 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7787 .channel_mode = alc883_3ST_2ch_modes,
7788 .input_mux = &alc883_lenovo_101e_capture_source,
7789 .unsol_event = alc883_lenovo_101e_unsol_event,
7790 .init_hook = alc883_lenovo_101e_all_automute,
7791 },
Kailang Yang272a5272007-05-14 11:00:38 +02007792 [ALC883_LENOVO_NB0763] = {
7793 .mixers = { alc883_lenovo_nb0763_mixer },
7794 .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
7795 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7796 .dac_nids = alc883_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02007797 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7798 .channel_mode = alc883_3ST_2ch_modes,
7799 .need_dac_fix = 1,
7800 .input_mux = &alc883_lenovo_nb0763_capture_source,
7801 .unsol_event = alc883_medion_md2_unsol_event,
7802 .init_hook = alc883_medion_md2_automute,
7803 },
7804 [ALC888_LENOVO_MS7195_DIG] = {
7805 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
7806 .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs},
7807 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7808 .dac_nids = alc883_dac_nids,
7809 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +02007810 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
7811 .channel_mode = alc883_3ST_6ch_modes,
7812 .need_dac_fix = 1,
7813 .input_mux = &alc883_capture_source,
7814 .unsol_event = alc883_lenovo_ms7195_unsol_event,
7815 .init_hook = alc888_lenovo_ms7195_front_automute,
Kailang Yang189609a2007-08-20 11:31:23 +02007816 },
7817 [ALC883_HAIER_W66] = {
7818 .mixers = { alc883_tagra_2ch_mixer},
7819 .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs},
7820 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7821 .dac_nids = alc883_dac_nids,
7822 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang189609a2007-08-20 11:31:23 +02007823 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7824 .channel_mode = alc883_3ST_2ch_modes,
7825 .input_mux = &alc883_capture_source,
7826 .unsol_event = alc883_haier_w66_unsol_event,
7827 .init_hook = alc883_haier_w66_automute,
Kailang Yang272a5272007-05-14 11:00:38 +02007828 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007829 [ALC888_6ST_HP] = {
7830 .mixers = { alc888_6st_hp_mixer, alc883_chmode_mixer },
7831 .init_verbs = { alc883_init_verbs, alc888_6st_hp_verbs },
Claudio Matsuokacd1e3b42007-07-06 12:10:01 +02007832 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7833 .dac_nids = alc883_dac_nids,
7834 .dig_out_nid = ALC883_DIGOUT_NID,
Claudio Matsuokacd1e3b42007-07-06 12:10:01 +02007835 .dig_in_nid = ALC883_DIGIN_NID,
7836 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
7837 .channel_mode = alc883_sixstack_modes,
7838 .input_mux = &alc883_capture_source,
7839 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007840 [ALC888_3ST_HP] = {
7841 .mixers = { alc888_3st_hp_mixer, alc883_chmode_mixer },
7842 .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007843 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7844 .dac_nids = alc883_dac_nids,
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007845 .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
7846 .channel_mode = alc888_3st_hp_modes,
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007847 .need_dac_fix = 1,
7848 .input_mux = &alc883_capture_source,
7849 },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007850 [ALC888_6ST_DELL] = {
7851 .mixers = { alc888_6st_dell_mixer, alc883_chmode_mixer },
7852 .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
7853 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7854 .dac_nids = alc883_dac_nids,
7855 .dig_out_nid = ALC883_DIGOUT_NID,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007856 .dig_in_nid = ALC883_DIGIN_NID,
7857 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
7858 .channel_mode = alc883_sixstack_modes,
7859 .input_mux = &alc883_capture_source,
7860 .unsol_event = alc888_6st_dell_unsol_event,
7861 .init_hook = alc888_6st_dell_front_automute,
7862 },
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007863 [ALC883_MITAC] = {
7864 .mixers = { alc883_mitac_mixer },
7865 .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
7866 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7867 .dac_nids = alc883_dac_nids,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007868 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7869 .channel_mode = alc883_3ST_2ch_modes,
7870 .input_mux = &alc883_capture_source,
7871 .unsol_event = alc883_mitac_unsol_event,
7872 .init_hook = alc883_mitac_automute,
7873 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007874};
7875
7876
7877/*
7878 * BIOS auto configuration
7879 */
7880static void alc883_auto_set_output_and_unmute(struct hda_codec *codec,
7881 hda_nid_t nid, int pin_type,
7882 int dac_idx)
7883{
7884 /* set as output */
7885 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007886 int idx;
7887
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007888 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007889 if (spec->multiout.dac_nids[dac_idx] == 0x25)
7890 idx = 4;
7891 else
7892 idx = spec->multiout.dac_nids[dac_idx] - 2;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007893 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
7894
7895}
7896
7897static void alc883_auto_init_multi_out(struct hda_codec *codec)
7898{
7899 struct alc_spec *spec = codec->spec;
7900 int i;
7901
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007902 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007903 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007904 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02007905 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007906 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02007907 alc883_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007908 i);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007909 }
7910}
7911
7912static void alc883_auto_init_hp_out(struct hda_codec *codec)
7913{
7914 struct alc_spec *spec = codec->spec;
7915 hda_nid_t pin;
7916
Takashi Iwaieb06ed82006-09-20 17:10:27 +02007917 pin = spec->autocfg.hp_pins[0];
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007918 if (pin) /* connect to front */
7919 /* use dac 0 */
7920 alc883_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007921 pin = spec->autocfg.speaker_pins[0];
7922 if (pin)
7923 alc883_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007924}
7925
7926#define alc883_is_input_pin(nid) alc880_is_input_pin(nid)
7927#define ALC883_PIN_CD_NID ALC880_PIN_CD_NID
7928
7929static void alc883_auto_init_analog_input(struct hda_codec *codec)
7930{
7931 struct alc_spec *spec = codec->spec;
7932 int i;
7933
7934 for (i = 0; i < AUTO_PIN_LAST; i++) {
7935 hda_nid_t nid = spec->autocfg.input_pins[i];
7936 if (alc883_is_input_pin(nid)) {
7937 snd_hda_codec_write(codec, nid, 0,
7938 AC_VERB_SET_PIN_WIDGET_CONTROL,
7939 (i <= AUTO_PIN_FRONT_MIC ?
7940 PIN_VREF80 : PIN_IN));
7941 if (nid != ALC883_PIN_CD_NID)
7942 snd_hda_codec_write(codec, nid, 0,
7943 AC_VERB_SET_AMP_GAIN_MUTE,
7944 AMP_OUT_MUTE);
7945 }
7946 }
7947}
7948
7949/* almost identical with ALC880 parser... */
7950static int alc883_parse_auto_config(struct hda_codec *codec)
7951{
7952 struct alc_spec *spec = codec->spec;
7953 int err = alc880_parse_auto_config(codec);
7954
7955 if (err < 0)
7956 return err;
Takashi Iwai776e1842007-08-29 15:07:11 +02007957 else if (!err)
7958 return 0; /* no config found */
7959
7960 err = alc_auto_add_mic_boost(codec);
7961 if (err < 0)
7962 return err;
7963
7964 /* hack - override the init verbs */
7965 spec->init_verbs[0] = alc883_auto_init_verbs;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007966 spec->mixers[spec->num_mixers] = alc883_capture_mixer;
7967 spec->num_mixers++;
Takashi Iwai776e1842007-08-29 15:07:11 +02007968
7969 return 1; /* config found */
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007970}
7971
7972/* additional initialization for auto-configuration model */
7973static void alc883_auto_init(struct hda_codec *codec)
7974{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007975 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007976 alc883_auto_init_multi_out(codec);
7977 alc883_auto_init_hp_out(codec);
7978 alc883_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007979 if (spec->unsol_event)
7980 alc_sku_automute(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007981}
7982
7983static int patch_alc883(struct hda_codec *codec)
7984{
7985 struct alc_spec *spec;
7986 int err, board_config;
7987
7988 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
7989 if (spec == NULL)
7990 return -ENOMEM;
7991
7992 codec->spec = spec;
7993
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007994 board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST,
7995 alc883_models,
7996 alc883_cfg_tbl);
7997 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007998 printk(KERN_INFO "hda_codec: Unknown model for ALC883, "
7999 "trying auto-probe from BIOS...\n");
8000 board_config = ALC883_AUTO;
8001 }
8002
8003 if (board_config == ALC883_AUTO) {
8004 /* automatic parse from the BIOS config */
8005 err = alc883_parse_auto_config(codec);
8006 if (err < 0) {
8007 alc_free(codec);
8008 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008009 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008010 printk(KERN_INFO
8011 "hda_codec: Cannot set up configuration "
8012 "from BIOS. Using base mode...\n");
8013 board_config = ALC883_3ST_2ch_DIG;
8014 }
8015 }
8016
8017 if (board_config != ALC883_AUTO)
8018 setup_preset(spec, &alc883_presets[board_config]);
8019
8020 spec->stream_name_analog = "ALC883 Analog";
8021 spec->stream_analog_playback = &alc883_pcm_analog_playback;
8022 spec->stream_analog_capture = &alc883_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01008023 spec->stream_analog_alt_capture = &alc883_pcm_analog_alt_capture;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008024
8025 spec->stream_name_digital = "ALC883 Digital";
8026 spec->stream_digital_playback = &alc883_pcm_digital_playback;
8027 spec->stream_digital_capture = &alc883_pcm_digital_capture;
8028
Takashi Iwaie1406342008-02-11 18:32:32 +01008029 spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
8030 spec->adc_nids = alc883_adc_nids;
8031 spec->capsrc_nids = alc883_capsrc_nids;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008032
Takashi Iwai2134ea42008-01-10 16:53:55 +01008033 spec->vmaster_nid = 0x0c;
8034
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008035 codec->patch_ops = alc_patch_ops;
8036 if (board_config == ALC883_AUTO)
8037 spec->init_hook = alc883_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02008038#ifdef CONFIG_SND_HDA_POWER_SAVE
8039 if (!spec->loopback.amplist)
8040 spec->loopback.amplist = alc883_loopbacks;
8041#endif
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008042
8043 return 0;
8044}
8045
8046/*
Kailang Yangdf694da2005-12-05 19:42:22 +01008047 * ALC262 support
8048 */
8049
8050#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID
8051#define ALC262_DIGIN_NID ALC880_DIGIN_NID
8052
8053#define alc262_dac_nids alc260_dac_nids
8054#define alc262_adc_nids alc882_adc_nids
8055#define alc262_adc_nids_alt alc882_adc_nids_alt
8056
8057#define alc262_modes alc260_modes
Takashi Iwaic5f2ea02005-12-06 18:54:31 +01008058#define alc262_capture_source alc882_capture_source
Kailang Yangdf694da2005-12-05 19:42:22 +01008059
8060static struct snd_kcontrol_new alc262_base_mixer[] = {
8061 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8062 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8063 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8064 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8065 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8066 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8067 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8068 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008069 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01008070 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8071 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008072 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01008073 /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01008074 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT), */
Kailang Yangdf694da2005-12-05 19:42:22 +01008075 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
8076 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8077 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8078 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01008079 { } /* end */
Takashi Iwai834be882006-03-01 14:16:17 +01008080};
8081
Kailang Yangccc656c2006-10-17 12:32:26 +02008082static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
8083 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8084 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8085 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8086 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8087 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8088 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8089 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8090 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008091 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008092 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8093 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008094 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008095 /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01008096 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT), */
Kailang Yangccc656c2006-10-17 12:32:26 +02008097 /*HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),*/
8098 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8099 { } /* end */
8100};
8101
Takashi Iwaice875f02008-01-28 18:17:43 +01008102/* update HP, line and mono-out pins according to the master switch */
8103static void alc262_hp_master_update(struct hda_codec *codec)
8104{
8105 struct alc_spec *spec = codec->spec;
8106 int val = spec->master_sw;
8107
8108 /* HP & line-out */
8109 snd_hda_codec_write_cache(codec, 0x1b, 0,
8110 AC_VERB_SET_PIN_WIDGET_CONTROL,
8111 val ? PIN_HP : 0);
8112 snd_hda_codec_write_cache(codec, 0x15, 0,
8113 AC_VERB_SET_PIN_WIDGET_CONTROL,
8114 val ? PIN_HP : 0);
8115 /* mono (speaker) depending on the HP jack sense */
8116 val = val && !spec->jack_present;
8117 snd_hda_codec_write_cache(codec, 0x16, 0,
8118 AC_VERB_SET_PIN_WIDGET_CONTROL,
8119 val ? PIN_OUT : 0);
8120}
8121
8122static void alc262_hp_bpc_automute(struct hda_codec *codec)
8123{
8124 struct alc_spec *spec = codec->spec;
8125 unsigned int presence;
8126 presence = snd_hda_codec_read(codec, 0x1b, 0,
8127 AC_VERB_GET_PIN_SENSE, 0);
8128 spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
8129 alc262_hp_master_update(codec);
8130}
8131
8132static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res)
8133{
8134 if ((res >> 26) != ALC880_HP_EVENT)
8135 return;
8136 alc262_hp_bpc_automute(codec);
8137}
8138
8139static void alc262_hp_wildwest_automute(struct hda_codec *codec)
8140{
8141 struct alc_spec *spec = codec->spec;
8142 unsigned int presence;
8143 presence = snd_hda_codec_read(codec, 0x15, 0,
8144 AC_VERB_GET_PIN_SENSE, 0);
8145 spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
8146 alc262_hp_master_update(codec);
8147}
8148
8149static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec,
8150 unsigned int res)
8151{
8152 if ((res >> 26) != ALC880_HP_EVENT)
8153 return;
8154 alc262_hp_wildwest_automute(codec);
8155}
8156
8157static int alc262_hp_master_sw_get(struct snd_kcontrol *kcontrol,
8158 struct snd_ctl_elem_value *ucontrol)
8159{
8160 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
8161 struct alc_spec *spec = codec->spec;
8162 *ucontrol->value.integer.value = spec->master_sw;
8163 return 0;
8164}
8165
8166static int alc262_hp_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 struct alc_spec *spec = codec->spec;
8171 int val = !!*ucontrol->value.integer.value;
8172
8173 if (val == spec->master_sw)
8174 return 0;
8175 spec->master_sw = val;
8176 alc262_hp_master_update(codec);
8177 return 1;
8178}
8179
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008180static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
Takashi Iwaice875f02008-01-28 18:17:43 +01008181 {
8182 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8183 .name = "Master Playback Switch",
8184 .info = snd_ctl_boolean_mono_info,
8185 .get = alc262_hp_master_sw_get,
8186 .put = alc262_hp_master_sw_put,
8187 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008188 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8189 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8190 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +01008191 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
8192 HDA_OUTPUT),
8193 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
8194 HDA_OUTPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008195 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8196 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008197 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008198 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8199 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008200 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008201 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8202 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8203 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8204 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8205 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
8206 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT),
8207 HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
8208 HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
8209 { } /* end */
8210};
8211
Kailang Yangcd7509a2007-01-26 18:33:17 +01008212static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
Takashi Iwaice875f02008-01-28 18:17:43 +01008213 {
8214 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8215 .name = "Master Playback Switch",
8216 .info = snd_ctl_boolean_mono_info,
8217 .get = alc262_hp_master_sw_get,
8218 .put = alc262_hp_master_sw_put,
8219 },
Kailang Yangcd7509a2007-01-26 18:33:17 +01008220 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8221 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8222 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8223 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +01008224 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
8225 HDA_OUTPUT),
8226 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
8227 HDA_OUTPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01008228 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
8229 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008230 HDA_CODEC_VOLUME("Front Mic Boost", 0x1a, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01008231 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
8232 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
8233 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8234 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8235 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
8236 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT),
8237 { } /* end */
8238};
8239
8240static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
8241 HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8242 HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008243 HDA_CODEC_VOLUME("Rear Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01008244 { } /* end */
8245};
8246
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008247/* mute/unmute internal speaker according to the hp jack and mute state */
8248static void alc262_hp_t5735_automute(struct hda_codec *codec, int force)
8249{
8250 struct alc_spec *spec = codec->spec;
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008251
8252 if (force || !spec->sense_updated) {
8253 unsigned int present;
8254 present = snd_hda_codec_read(codec, 0x15, 0,
8255 AC_VERB_GET_PIN_SENSE, 0);
Takashi Iwai4bb26132008-01-28 18:12:42 +01008256 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008257 spec->sense_updated = 1;
8258 }
Takashi Iwai4bb26132008-01-28 18:12:42 +01008259 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0, HDA_AMP_MUTE,
8260 spec->jack_present ? HDA_AMP_MUTE : 0);
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008261}
8262
8263static void alc262_hp_t5735_unsol_event(struct hda_codec *codec,
8264 unsigned int res)
8265{
8266 if ((res >> 26) != ALC880_HP_EVENT)
8267 return;
8268 alc262_hp_t5735_automute(codec, 1);
8269}
8270
8271static void alc262_hp_t5735_init_hook(struct hda_codec *codec)
8272{
8273 alc262_hp_t5735_automute(codec, 1);
8274}
8275
8276static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +01008277 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8278 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008279 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8280 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8281 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8282 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8283 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8284 { } /* end */
8285};
8286
8287static struct hda_verb alc262_hp_t5735_verbs[] = {
8288 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8289 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8290
8291 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8292 { }
8293};
8294
Kailang Yang8c427222008-01-10 13:03:59 +01008295static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
Takashi Iwaif2f48e12008-01-28 18:14:43 +01008296 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8297 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01008298 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
8299 HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +01008300 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
8301 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
8302 { } /* end */
8303};
8304
8305static struct hda_verb alc262_hp_rp5700_verbs[] = {
8306 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8307 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8308 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8309 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8310 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8311 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
8312 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
8313 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
8314 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
8315 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
8316 {}
8317};
8318
8319static struct hda_input_mux alc262_hp_rp5700_capture_source = {
8320 .num_items = 1,
8321 .items = {
8322 { "Line", 0x1 },
8323 },
8324};
8325
Takashi Iwai0724ea22007-08-23 00:31:43 +02008326/* bind hp and internal speaker mute (with plug check) */
8327static int alc262_sony_master_sw_put(struct snd_kcontrol *kcontrol,
8328 struct snd_ctl_elem_value *ucontrol)
8329{
8330 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
8331 long *valp = ucontrol->value.integer.value;
8332 int change;
8333
8334 /* change hp mute */
8335 change = snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0,
8336 HDA_AMP_MUTE,
8337 valp[0] ? 0 : HDA_AMP_MUTE);
8338 change |= snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0,
8339 HDA_AMP_MUTE,
8340 valp[1] ? 0 : HDA_AMP_MUTE);
8341 if (change) {
8342 /* change speaker according to HP jack state */
8343 struct alc_spec *spec = codec->spec;
8344 unsigned int mute;
8345 if (spec->jack_present)
8346 mute = HDA_AMP_MUTE;
8347 else
8348 mute = snd_hda_codec_amp_read(codec, 0x15, 0,
8349 HDA_OUTPUT, 0);
8350 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8351 HDA_AMP_MUTE, mute);
8352 }
8353 return change;
8354}
Takashi Iwai5b319542007-07-26 11:49:22 +02008355
Kailang Yang272a5272007-05-14 11:00:38 +02008356static struct snd_kcontrol_new alc262_sony_mixer[] = {
Takashi Iwai0724ea22007-08-23 00:31:43 +02008357 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8358 {
8359 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8360 .name = "Master Playback Switch",
8361 .info = snd_hda_mixer_amp_switch_info,
8362 .get = snd_hda_mixer_amp_switch_get,
8363 .put = alc262_sony_master_sw_put,
8364 .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
8365 },
Kailang Yang272a5272007-05-14 11:00:38 +02008366 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8367 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8368 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8369 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
8370 { } /* end */
8371};
8372
Kailang Yang83c34212007-07-05 11:43:05 +02008373static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
8374 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8375 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8376 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8377 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8378 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8379 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8380 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
8381 { } /* end */
8382};
Kailang Yang272a5272007-05-14 11:00:38 +02008383
Kailang Yangdf694da2005-12-05 19:42:22 +01008384#define alc262_capture_mixer alc882_capture_mixer
8385#define alc262_capture_alt_mixer alc882_capture_alt_mixer
8386
8387/*
8388 * generic initialization of ADC, input mixers and output mixers
8389 */
8390static struct hda_verb alc262_init_verbs[] = {
8391 /*
8392 * Unmute ADC0-2 and set the default input to mic-in
8393 */
8394 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8395 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8396 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8397 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8398 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8399 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8400
Takashi Iwaicb53c622007-08-10 17:21:45 +02008401 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01008402 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008403 * Note: PASD motherboards uses the Line In 2 as the input for
8404 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01008405 */
8406 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02008407 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8408 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8409 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8410 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8411 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01008412
8413 /*
8414 * Set up output mixers (0x0c - 0x0e)
8415 */
8416 /* set vol=0 to output mixers */
8417 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8418 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8419 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8420 /* set up input amps for analog loopback */
8421 /* Amp Indices: DAC = 0, mixer = 1 */
8422 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8423 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8424 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8425 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8426 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8427 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8428
8429 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
8430 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
8431 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
8432 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
8433 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
8434 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
8435
8436 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8437 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8438 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8439 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8440 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8441
8442 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8443 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
8444
8445 /* FIXME: use matrix-type input source selection */
8446 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8447 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8448 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8449 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
8450 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
8451 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
8452 /* Input mixer2 */
8453 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8454 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
8455 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
8456 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
8457 /* Input mixer3 */
8458 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8459 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
8460 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008461 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
Kailang Yangdf694da2005-12-05 19:42:22 +01008462
8463 { }
8464};
8465
Kailang Yangccc656c2006-10-17 12:32:26 +02008466static struct hda_verb alc262_hippo_unsol_verbs[] = {
8467 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
8468 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8469 {}
8470};
8471
8472static struct hda_verb alc262_hippo1_unsol_verbs[] = {
8473 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
8474 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
8475 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8476
8477 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
8478 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8479 {}
8480};
8481
Kailang Yang272a5272007-05-14 11:00:38 +02008482static struct hda_verb alc262_sony_unsol_verbs[] = {
8483 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
8484 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8485 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic
8486
8487 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
8488 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8489};
8490
Kailang Yangccc656c2006-10-17 12:32:26 +02008491/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai5b319542007-07-26 11:49:22 +02008492static void alc262_hippo_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02008493{
8494 struct alc_spec *spec = codec->spec;
8495 unsigned int mute;
Takashi Iwai5b319542007-07-26 11:49:22 +02008496 unsigned int present;
Kailang Yangccc656c2006-10-17 12:32:26 +02008497
Takashi Iwai5b319542007-07-26 11:49:22 +02008498 /* need to execute and sync at first */
8499 snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
8500 present = snd_hda_codec_read(codec, 0x15, 0,
8501 AC_VERB_GET_PIN_SENSE, 0);
8502 spec->jack_present = (present & 0x80000000) != 0;
Kailang Yangccc656c2006-10-17 12:32:26 +02008503 if (spec->jack_present) {
8504 /* mute internal speaker */
Takashi Iwai47fd8302007-08-10 17:11:07 +02008505 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8506 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangccc656c2006-10-17 12:32:26 +02008507 } else {
8508 /* unmute internal speaker if necessary */
8509 mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
Takashi Iwai47fd8302007-08-10 17:11:07 +02008510 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8511 HDA_AMP_MUTE, mute);
Kailang Yangccc656c2006-10-17 12:32:26 +02008512 }
8513}
8514
8515/* unsolicited event for HP jack sensing */
8516static void alc262_hippo_unsol_event(struct hda_codec *codec,
8517 unsigned int res)
8518{
8519 if ((res >> 26) != ALC880_HP_EVENT)
8520 return;
Takashi Iwai5b319542007-07-26 11:49:22 +02008521 alc262_hippo_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02008522}
8523
Takashi Iwai5b319542007-07-26 11:49:22 +02008524static void alc262_hippo1_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02008525{
Kailang Yangccc656c2006-10-17 12:32:26 +02008526 unsigned int mute;
Takashi Iwai5b319542007-07-26 11:49:22 +02008527 unsigned int present;
Kailang Yangccc656c2006-10-17 12:32:26 +02008528
Takashi Iwai5b319542007-07-26 11:49:22 +02008529 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
8530 present = snd_hda_codec_read(codec, 0x1b, 0,
8531 AC_VERB_GET_PIN_SENSE, 0);
8532 present = (present & 0x80000000) != 0;
8533 if (present) {
Kailang Yangccc656c2006-10-17 12:32:26 +02008534 /* mute internal speaker */
Takashi Iwai47fd8302007-08-10 17:11:07 +02008535 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8536 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangccc656c2006-10-17 12:32:26 +02008537 } else {
8538 /* unmute internal speaker if necessary */
8539 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
Takashi Iwai47fd8302007-08-10 17:11:07 +02008540 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8541 HDA_AMP_MUTE, mute);
Kailang Yangccc656c2006-10-17 12:32:26 +02008542 }
8543}
8544
8545/* unsolicited event for HP jack sensing */
8546static void alc262_hippo1_unsol_event(struct hda_codec *codec,
8547 unsigned int res)
8548{
8549 if ((res >> 26) != ALC880_HP_EVENT)
8550 return;
Takashi Iwai5b319542007-07-26 11:49:22 +02008551 alc262_hippo1_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02008552}
8553
Takashi Iwai834be882006-03-01 14:16:17 +01008554/*
8555 * fujitsu model
8556 * 0x14 = headphone/spdif-out, 0x15 = internal speaker
8557 */
8558
8559#define ALC_HP_EVENT 0x37
8560
8561static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
8562 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
8563 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8564 {}
8565};
8566
8567static struct hda_input_mux alc262_fujitsu_capture_source = {
Takashi Iwai39d3ed32007-10-12 15:03:48 +02008568 .num_items = 3,
Takashi Iwai834be882006-03-01 14:16:17 +01008569 .items = {
8570 { "Mic", 0x0 },
Takashi Iwai39d3ed32007-10-12 15:03:48 +02008571 { "Int Mic", 0x1 },
Takashi Iwai834be882006-03-01 14:16:17 +01008572 { "CD", 0x4 },
8573 },
8574};
8575
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008576static struct hda_input_mux alc262_HP_capture_source = {
8577 .num_items = 5,
8578 .items = {
8579 { "Mic", 0x0 },
zhejiangaccbe492007-08-31 12:36:05 +02008580 { "Front Mic", 0x1 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008581 { "Line", 0x2 },
8582 { "CD", 0x4 },
8583 { "AUX IN", 0x6 },
8584 },
8585};
8586
zhejiangaccbe492007-08-31 12:36:05 +02008587static struct hda_input_mux alc262_HP_D7000_capture_source = {
8588 .num_items = 4,
8589 .items = {
8590 { "Mic", 0x0 },
8591 { "Front Mic", 0x2 },
8592 { "Line", 0x1 },
8593 { "CD", 0x4 },
8594 },
8595};
8596
Takashi Iwai834be882006-03-01 14:16:17 +01008597/* mute/unmute internal speaker according to the hp jack and mute state */
8598static void alc262_fujitsu_automute(struct hda_codec *codec, int force)
8599{
8600 struct alc_spec *spec = codec->spec;
8601 unsigned int mute;
8602
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008603 if (force || !spec->sense_updated) {
Takashi Iwai834be882006-03-01 14:16:17 +01008604 unsigned int present;
8605 /* need to execute and sync at first */
8606 snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
8607 present = snd_hda_codec_read(codec, 0x14, 0,
8608 AC_VERB_GET_PIN_SENSE, 0);
8609 spec->jack_present = (present & 0x80000000) != 0;
8610 spec->sense_updated = 1;
8611 }
8612 if (spec->jack_present) {
8613 /* mute internal speaker */
Takashi Iwai47fd8302007-08-10 17:11:07 +02008614 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8615 HDA_AMP_MUTE, HDA_AMP_MUTE);
Takashi Iwai834be882006-03-01 14:16:17 +01008616 } else {
8617 /* unmute internal speaker if necessary */
8618 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
Takashi Iwai47fd8302007-08-10 17:11:07 +02008619 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8620 HDA_AMP_MUTE, mute);
Takashi Iwai834be882006-03-01 14:16:17 +01008621 }
8622}
8623
8624/* unsolicited event for HP jack sensing */
8625static void alc262_fujitsu_unsol_event(struct hda_codec *codec,
8626 unsigned int res)
8627{
8628 if ((res >> 26) != ALC_HP_EVENT)
8629 return;
8630 alc262_fujitsu_automute(codec, 1);
8631}
8632
8633/* bind volumes of both NID 0x0c and 0x0d */
Takashi Iwaicca3b372007-08-10 17:12:15 +02008634static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
8635 .ops = &snd_hda_bind_vol,
8636 .values = {
8637 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
8638 HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
8639 0
8640 },
8641};
Takashi Iwai834be882006-03-01 14:16:17 +01008642
8643/* bind hp and internal speaker mute (with plug check) */
8644static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
8645 struct snd_ctl_elem_value *ucontrol)
8646{
8647 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
8648 long *valp = ucontrol->value.integer.value;
8649 int change;
8650
8651 change = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02008652 HDA_AMP_MUTE,
8653 valp[0] ? 0 : HDA_AMP_MUTE);
Takashi Iwai834be882006-03-01 14:16:17 +01008654 change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02008655 HDA_AMP_MUTE,
8656 valp[1] ? 0 : HDA_AMP_MUTE);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02008657 if (change)
8658 alc262_fujitsu_automute(codec, 0);
Takashi Iwai834be882006-03-01 14:16:17 +01008659 return change;
8660}
8661
8662static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02008663 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai834be882006-03-01 14:16:17 +01008664 {
8665 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8666 .name = "Master Playback Switch",
8667 .info = snd_hda_mixer_amp_switch_info,
8668 .get = snd_hda_mixer_amp_switch_get,
8669 .put = alc262_fujitsu_master_sw_put,
8670 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
8671 },
8672 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8673 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8674 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8675 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8676 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai39d3ed32007-10-12 15:03:48 +02008677 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8678 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8679 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +01008680 { } /* end */
8681};
8682
Takashi Iwai304dcaa2006-07-25 14:51:16 +02008683/* additional init verbs for Benq laptops */
8684static struct hda_verb alc262_EAPD_verbs[] = {
8685 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
8686 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
8687 {}
8688};
8689
Kailang Yang83c34212007-07-05 11:43:05 +02008690static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
8691 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8692 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
8693
8694 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
8695 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
8696 {}
8697};
8698
Tobin Davisf651b502007-10-26 12:40:47 +02008699/* Samsung Q1 Ultra Vista model setup */
8700static struct snd_kcontrol_new alc262_ultra_mixer[] = {
8701 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8702 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8703 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8704 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8705 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
8706 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
8707 { } /* end */
8708};
8709
8710static struct hda_verb alc262_ultra_verbs[] = {
8711 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
8712 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8713 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
8714 /* Mic is on Node 0x19 */
8715 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
8716 {0x22, AC_VERB_SET_CONNECT_SEL, 0x01},
8717 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
8718 {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
8719 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
8720 {0x24, AC_VERB_SET_CONNECT_SEL, 0x01},
8721 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
8722 {}
8723};
8724
8725static struct hda_input_mux alc262_ultra_capture_source = {
8726 .num_items = 1,
8727 .items = {
8728 { "Mic", 0x1 },
8729 },
8730};
8731
8732/* mute/unmute internal speaker according to the hp jack and mute state */
8733static void alc262_ultra_automute(struct hda_codec *codec)
8734{
8735 struct alc_spec *spec = codec->spec;
8736 unsigned int mute;
8737 unsigned int present;
8738
8739 /* need to execute and sync at first */
8740 snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
8741 present = snd_hda_codec_read(codec, 0x15, 0,
8742 AC_VERB_GET_PIN_SENSE, 0);
8743 spec->jack_present = (present & 0x80000000) != 0;
8744 if (spec->jack_present) {
8745 /* mute internal speaker */
8746 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8747 HDA_AMP_MUTE, HDA_AMP_MUTE);
8748 } else {
8749 /* unmute internal speaker if necessary */
8750 mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
8751 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8752 HDA_AMP_MUTE, mute);
8753 }
8754}
8755
8756/* unsolicited event for HP jack sensing */
8757static void alc262_ultra_unsol_event(struct hda_codec *codec,
8758 unsigned int res)
8759{
8760 if ((res >> 26) != ALC880_HP_EVENT)
8761 return;
8762 alc262_ultra_automute(codec);
8763}
8764
Kailang Yangdf694da2005-12-05 19:42:22 +01008765/* add playback controls from the parsed DAC table */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008766static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
8767 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +01008768{
8769 hda_nid_t nid;
8770 int err;
8771
8772 spec->multiout.num_dacs = 1; /* only use one dac */
8773 spec->multiout.dac_nids = spec->private_dac_nids;
8774 spec->multiout.dac_nids[0] = 2;
8775
8776 nid = cfg->line_out_pins[0];
8777 if (nid) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008778 err = add_control(spec, ALC_CTL_WIDGET_VOL,
8779 "Front Playback Volume",
8780 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT));
8781 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008782 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008783 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
8784 "Front Playback Switch",
8785 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
8786 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008787 return err;
8788 }
8789
Takashi Iwai82bc9552006-03-21 11:24:42 +01008790 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01008791 if (nid) {
8792 if (nid == 0x16) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008793 err = add_control(spec, ALC_CTL_WIDGET_VOL,
8794 "Speaker Playback Volume",
8795 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
8796 HDA_OUTPUT));
8797 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008798 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008799 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
8800 "Speaker Playback Switch",
8801 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
8802 HDA_OUTPUT));
8803 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008804 return err;
8805 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008806 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
8807 "Speaker Playback Switch",
8808 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
8809 HDA_OUTPUT));
8810 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008811 return err;
8812 }
8813 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02008814 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01008815 if (nid) {
8816 /* spec->multiout.hp_nid = 2; */
8817 if (nid == 0x16) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008818 err = add_control(spec, ALC_CTL_WIDGET_VOL,
8819 "Headphone Playback Volume",
8820 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
8821 HDA_OUTPUT));
8822 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008823 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008824 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
8825 "Headphone Playback Switch",
8826 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
8827 HDA_OUTPUT));
8828 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008829 return err;
8830 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008831 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
8832 "Headphone Playback Switch",
8833 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
8834 HDA_OUTPUT));
8835 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008836 return err;
8837 }
8838 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008839 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01008840}
8841
8842/* identical with ALC880 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008843#define alc262_auto_create_analog_input_ctls \
8844 alc880_auto_create_analog_input_ctls
Kailang Yangdf694da2005-12-05 19:42:22 +01008845
8846/*
8847 * generic initialization of ADC, input mixers and output mixers
8848 */
8849static struct hda_verb alc262_volume_init_verbs[] = {
8850 /*
8851 * Unmute ADC0-2 and set the default input to mic-in
8852 */
8853 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8854 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8855 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8856 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8857 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8858 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8859
Takashi Iwaicb53c622007-08-10 17:21:45 +02008860 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01008861 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008862 * Note: PASD motherboards uses the Line In 2 as the input for
8863 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01008864 */
8865 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02008866 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8867 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8868 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8869 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8870 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01008871
8872 /*
8873 * Set up output mixers (0x0c - 0x0f)
8874 */
8875 /* set vol=0 to output mixers */
8876 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8877 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8878 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8879
8880 /* set up input amps for analog loopback */
8881 /* Amp Indices: DAC = 0, mixer = 1 */
8882 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8883 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8884 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8885 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8886 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8887 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8888
8889 /* FIXME: use matrix-type input source selection */
8890 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8891 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8892 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8893 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
8894 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
8895 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
8896 /* Input mixer2 */
8897 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8898 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
8899 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
8900 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
8901 /* Input mixer3 */
8902 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8903 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
8904 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
8905 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
8906
8907 { }
8908};
8909
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008910static struct hda_verb alc262_HP_BPC_init_verbs[] = {
8911 /*
8912 * Unmute ADC0-2 and set the default input to mic-in
8913 */
8914 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8915 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8916 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8917 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8918 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8919 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8920
Takashi Iwaicb53c622007-08-10 17:21:45 +02008921 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008922 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008923 * Note: PASD motherboards uses the Line In 2 as the input for
8924 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008925 */
8926 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02008927 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8928 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8929 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8930 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8931 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8932 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
8933 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008934
8935 /*
8936 * Set up output mixers (0x0c - 0x0e)
8937 */
8938 /* set vol=0 to output mixers */
8939 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8940 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8941 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8942
8943 /* set up input amps for analog loopback */
8944 /* Amp Indices: DAC = 0, mixer = 1 */
8945 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8946 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8947 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8948 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8949 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8950 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8951
Takashi Iwaice875f02008-01-28 18:17:43 +01008952 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008953 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8954 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8955
8956 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8957 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8958
8959 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
8960 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8961
8962 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
8963 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
8964 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
8965 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
8966 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
8967
8968 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
8969 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
8970 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
8971 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
8972 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
8973 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
8974
8975
8976 /* FIXME: use matrix-type input source selection */
8977 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8978 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8979 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8980 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
8981 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
8982 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
8983 /* Input mixer2 */
8984 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8985 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
8986 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
8987 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
8988 /* Input mixer3 */
8989 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8990 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
8991 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
8992 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
8993
Takashi Iwaice875f02008-01-28 18:17:43 +01008994 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8995
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008996 { }
8997};
8998
Kailang Yangcd7509a2007-01-26 18:33:17 +01008999static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
9000 /*
9001 * Unmute ADC0-2 and set the default input to mic-in
9002 */
9003 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
9004 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9005 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
9006 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9007 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
9008 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9009
Takashi Iwaicb53c622007-08-10 17:21:45 +02009010 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangcd7509a2007-01-26 18:33:17 +01009011 * mixer widget
9012 * Note: PASD motherboards uses the Line In 2 as the input for front
9013 * panel mic (mic 2)
9014 */
9015 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02009016 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9017 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9018 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
9019 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
9020 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
9021 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
9022 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
9023 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Kailang Yangcd7509a2007-01-26 18:33:17 +01009024 /*
9025 * Set up output mixers (0x0c - 0x0e)
9026 */
9027 /* set vol=0 to output mixers */
9028 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9029 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9030 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9031
9032 /* set up input amps for analog loopback */
9033 /* Amp Indices: DAC = 0, mixer = 1 */
9034 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9035 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9036 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9037 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9038 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9039 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9040
9041
9042 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
9043 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
9044 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
9045 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
9046 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
9047 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
9048 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
9049
9050 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
9051 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
9052
9053 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9054 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
9055
9056 /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
9057 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9058 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9059 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
9060 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9061 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9062
9063 /* FIXME: use matrix-type input source selection */
9064 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
9065 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
9066 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
9067 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
9068 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
9069 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
9070 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
9071 /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
9072 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
9073 /* Input mixer2 */
9074 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9075 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
9076 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
9077 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
9078 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
9079 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
9080 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
9081 /* Input mixer3 */
9082 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9083 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
9084 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
9085 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
9086 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
9087 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
9088 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
9089
Takashi Iwaice875f02008-01-28 18:17:43 +01009090 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9091
Kailang Yangcd7509a2007-01-26 18:33:17 +01009092 { }
9093};
9094
Takashi Iwaicb53c622007-08-10 17:21:45 +02009095#ifdef CONFIG_SND_HDA_POWER_SAVE
9096#define alc262_loopbacks alc880_loopbacks
9097#endif
9098
Kailang Yangdf694da2005-12-05 19:42:22 +01009099/* pcm configuration: identiacal with ALC880 */
9100#define alc262_pcm_analog_playback alc880_pcm_analog_playback
9101#define alc262_pcm_analog_capture alc880_pcm_analog_capture
9102#define alc262_pcm_digital_playback alc880_pcm_digital_playback
9103#define alc262_pcm_digital_capture alc880_pcm_digital_capture
9104
9105/*
9106 * BIOS auto configuration
9107 */
9108static int alc262_parse_auto_config(struct hda_codec *codec)
9109{
9110 struct alc_spec *spec = codec->spec;
9111 int err;
9112 static hda_nid_t alc262_ignore[] = { 0x1d, 0 };
9113
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009114 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
9115 alc262_ignore);
9116 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009117 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009118 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +01009119 return 0; /* can't find valid BIOS pin config */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009120 err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
9121 if (err < 0)
9122 return err;
9123 err = alc262_auto_create_analog_input_ctls(spec, &spec->autocfg);
9124 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009125 return err;
9126
9127 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
9128
9129 if (spec->autocfg.dig_out_pin)
9130 spec->multiout.dig_out_nid = ALC262_DIGOUT_NID;
9131 if (spec->autocfg.dig_in_pin)
9132 spec->dig_in_nid = ALC262_DIGIN_NID;
9133
9134 if (spec->kctl_alloc)
9135 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
9136
9137 spec->init_verbs[spec->num_init_verbs++] = alc262_volume_init_verbs;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02009138 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +01009139 spec->input_mux = &spec->private_imux;
9140
Takashi Iwai776e1842007-08-29 15:07:11 +02009141 err = alc_auto_add_mic_boost(codec);
9142 if (err < 0)
9143 return err;
9144
Kailang Yangdf694da2005-12-05 19:42:22 +01009145 return 1;
9146}
9147
9148#define alc262_auto_init_multi_out alc882_auto_init_multi_out
9149#define alc262_auto_init_hp_out alc882_auto_init_hp_out
9150#define alc262_auto_init_analog_input alc882_auto_init_analog_input
9151
9152
9153/* init callback for auto-configuration model -- overriding the default init */
Takashi Iwaiae6b8132006-03-03 16:47:17 +01009154static void alc262_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01009155{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01009156 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01009157 alc262_auto_init_multi_out(codec);
9158 alc262_auto_init_hp_out(codec);
9159 alc262_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01009160 if (spec->unsol_event)
9161 alc_sku_automute(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01009162}
9163
9164/*
9165 * configuration and preset
9166 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009167static const char *alc262_models[ALC262_MODEL_LAST] = {
9168 [ALC262_BASIC] = "basic",
9169 [ALC262_HIPPO] = "hippo",
9170 [ALC262_HIPPO_1] = "hippo_1",
9171 [ALC262_FUJITSU] = "fujitsu",
9172 [ALC262_HP_BPC] = "hp-bpc",
Kailang Yangcd7509a2007-01-26 18:33:17 +01009173 [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
Takashi Iwai61dc35d2007-11-14 12:26:44 +01009174 [ALC262_HP_TC_T5735] = "hp-tc-t5735",
Kailang Yang8c427222008-01-10 13:03:59 +01009175 [ALC262_HP_RP5700] = "hp-rp5700",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009176 [ALC262_BENQ_ED8] = "benq",
Takashi Iwai0f405022007-07-06 12:24:11 +02009177 [ALC262_BENQ_T31] = "benq-t31",
9178 [ALC262_SONY_ASSAMD] = "sony-assamd",
Tobin Davisf651b502007-10-26 12:40:47 +02009179 [ALC262_ULTRA] = "ultra",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009180 [ALC262_AUTO] = "auto",
9181};
9182
9183static struct snd_pci_quirk alc262_cfg_tbl[] = {
9184 SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
9185 SND_PCI_QUIRK(0x103c, 0x12fe, "HP xw9400", ALC262_HP_BPC),
Kailang Yang7d87de22007-06-05 12:17:21 +02009186 SND_PCI_QUIRK(0x103c, 0x12ff, "HP xw4550", ALC262_HP_BPC),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009187 SND_PCI_QUIRK(0x103c, 0x1306, "HP xw8600", ALC262_HP_BPC),
9188 SND_PCI_QUIRK(0x103c, 0x1307, "HP xw6600", ALC262_HP_BPC),
Kailang Yang7d87de22007-06-05 12:17:21 +02009189 SND_PCI_QUIRK(0x103c, 0x1308, "HP xw4600", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +01009190 SND_PCI_QUIRK(0x103c, 0x1309, "HP xw4*00", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +01009191 SND_PCI_QUIRK(0x103c, 0x130a, "HP xw6*00", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +01009192 SND_PCI_QUIRK(0x103c, 0x130b, "HP xw8*00", ALC262_HP_BPC),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009193 SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009194 SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009195 SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009196 SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009197 SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009198 SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009199 SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009200 SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009201 SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
9202 SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
9203 SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009204 SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
9205 ALC262_HP_TC_T5735),
Kailang Yang8c427222008-01-10 13:03:59 +01009206 SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009207 SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009208 SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009209 SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
9210 SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD),
9211 SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009212 SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
Tony Vroon3f1eeae2008-02-25 16:44:13 +01009213 SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009214 SND_PCI_QUIRK(0x144d, 0xc032, "Samsung Q1 Ultra", ALC262_ULTRA),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009215 SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
Kailang Yang83c34212007-07-05 11:43:05 +02009216 SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009217 SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
Kailang Yangdf694da2005-12-05 19:42:22 +01009218 {}
9219};
9220
9221static struct alc_config_preset alc262_presets[] = {
9222 [ALC262_BASIC] = {
9223 .mixers = { alc262_base_mixer },
9224 .init_verbs = { alc262_init_verbs },
9225 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9226 .dac_nids = alc262_dac_nids,
9227 .hp_nid = 0x03,
9228 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9229 .channel_mode = alc262_modes,
Takashi Iwaia3bcba32005-12-06 19:05:29 +01009230 .input_mux = &alc262_capture_source,
Kailang Yangdf694da2005-12-05 19:42:22 +01009231 },
Kailang Yangccc656c2006-10-17 12:32:26 +02009232 [ALC262_HIPPO] = {
9233 .mixers = { alc262_base_mixer },
9234 .init_verbs = { alc262_init_verbs, alc262_hippo_unsol_verbs},
9235 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9236 .dac_nids = alc262_dac_nids,
9237 .hp_nid = 0x03,
9238 .dig_out_nid = ALC262_DIGOUT_NID,
9239 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9240 .channel_mode = alc262_modes,
9241 .input_mux = &alc262_capture_source,
9242 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +02009243 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +02009244 },
9245 [ALC262_HIPPO_1] = {
9246 .mixers = { alc262_hippo1_mixer },
9247 .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
9248 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9249 .dac_nids = alc262_dac_nids,
9250 .hp_nid = 0x02,
9251 .dig_out_nid = ALC262_DIGOUT_NID,
9252 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9253 .channel_mode = alc262_modes,
9254 .input_mux = &alc262_capture_source,
9255 .unsol_event = alc262_hippo1_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +02009256 .init_hook = alc262_hippo1_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +02009257 },
Takashi Iwai834be882006-03-01 14:16:17 +01009258 [ALC262_FUJITSU] = {
9259 .mixers = { alc262_fujitsu_mixer },
Takashi Iwai39d3ed32007-10-12 15:03:48 +02009260 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
9261 alc262_fujitsu_unsol_verbs },
Takashi Iwai834be882006-03-01 14:16:17 +01009262 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9263 .dac_nids = alc262_dac_nids,
9264 .hp_nid = 0x03,
9265 .dig_out_nid = ALC262_DIGOUT_NID,
9266 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9267 .channel_mode = alc262_modes,
9268 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01009269 .unsol_event = alc262_fujitsu_unsol_event,
Takashi Iwai834be882006-03-01 14:16:17 +01009270 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009271 [ALC262_HP_BPC] = {
9272 .mixers = { alc262_HP_BPC_mixer },
9273 .init_verbs = { alc262_HP_BPC_init_verbs },
9274 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9275 .dac_nids = alc262_dac_nids,
9276 .hp_nid = 0x03,
9277 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9278 .channel_mode = alc262_modes,
9279 .input_mux = &alc262_HP_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +01009280 .unsol_event = alc262_hp_bpc_unsol_event,
9281 .init_hook = alc262_hp_bpc_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009282 },
Kailang Yangcd7509a2007-01-26 18:33:17 +01009283 [ALC262_HP_BPC_D7000_WF] = {
9284 .mixers = { alc262_HP_BPC_WildWest_mixer },
9285 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
9286 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9287 .dac_nids = alc262_dac_nids,
9288 .hp_nid = 0x03,
9289 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9290 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +02009291 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +01009292 .unsol_event = alc262_hp_wildwest_unsol_event,
9293 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009294 },
Kailang Yangcd7509a2007-01-26 18:33:17 +01009295 [ALC262_HP_BPC_D7000_WL] = {
9296 .mixers = { alc262_HP_BPC_WildWest_mixer,
9297 alc262_HP_BPC_WildWest_option_mixer },
9298 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
9299 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9300 .dac_nids = alc262_dac_nids,
9301 .hp_nid = 0x03,
9302 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9303 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +02009304 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +01009305 .unsol_event = alc262_hp_wildwest_unsol_event,
9306 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009307 },
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009308 [ALC262_HP_TC_T5735] = {
9309 .mixers = { alc262_hp_t5735_mixer },
9310 .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
9311 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9312 .dac_nids = alc262_dac_nids,
9313 .hp_nid = 0x03,
9314 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9315 .channel_mode = alc262_modes,
9316 .input_mux = &alc262_capture_source,
9317 .unsol_event = alc262_hp_t5735_unsol_event,
9318 .init_hook = alc262_hp_t5735_init_hook,
Kailang Yang8c427222008-01-10 13:03:59 +01009319 },
9320 [ALC262_HP_RP5700] = {
9321 .mixers = { alc262_hp_rp5700_mixer },
9322 .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
9323 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9324 .dac_nids = alc262_dac_nids,
9325 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9326 .channel_mode = alc262_modes,
9327 .input_mux = &alc262_hp_rp5700_capture_source,
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009328 },
Takashi Iwai304dcaa2006-07-25 14:51:16 +02009329 [ALC262_BENQ_ED8] = {
9330 .mixers = { alc262_base_mixer },
9331 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
9332 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9333 .dac_nids = alc262_dac_nids,
9334 .hp_nid = 0x03,
9335 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9336 .channel_mode = alc262_modes,
9337 .input_mux = &alc262_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009338 },
Kailang Yang272a5272007-05-14 11:00:38 +02009339 [ALC262_SONY_ASSAMD] = {
9340 .mixers = { alc262_sony_mixer },
9341 .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs},
9342 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9343 .dac_nids = alc262_dac_nids,
9344 .hp_nid = 0x02,
9345 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9346 .channel_mode = alc262_modes,
9347 .input_mux = &alc262_capture_source,
9348 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +02009349 .init_hook = alc262_hippo_automute,
Kailang Yang83c34212007-07-05 11:43:05 +02009350 },
9351 [ALC262_BENQ_T31] = {
9352 .mixers = { alc262_benq_t31_mixer },
9353 .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs, alc262_hippo_unsol_verbs },
9354 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9355 .dac_nids = alc262_dac_nids,
9356 .hp_nid = 0x03,
9357 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9358 .channel_mode = alc262_modes,
9359 .input_mux = &alc262_capture_source,
9360 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +02009361 .init_hook = alc262_hippo_automute,
Kailang Yang272a5272007-05-14 11:00:38 +02009362 },
Tobin Davisf651b502007-10-26 12:40:47 +02009363 [ALC262_ULTRA] = {
9364 .mixers = { alc262_ultra_mixer },
9365 .init_verbs = { alc262_init_verbs, alc262_ultra_verbs },
9366 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9367 .dac_nids = alc262_dac_nids,
9368 .hp_nid = 0x03,
9369 .dig_out_nid = ALC262_DIGOUT_NID,
9370 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9371 .channel_mode = alc262_modes,
9372 .input_mux = &alc262_ultra_capture_source,
9373 .unsol_event = alc262_ultra_unsol_event,
9374 .init_hook = alc262_ultra_automute,
9375 },
Kailang Yangdf694da2005-12-05 19:42:22 +01009376};
9377
9378static int patch_alc262(struct hda_codec *codec)
9379{
9380 struct alc_spec *spec;
9381 int board_config;
9382 int err;
9383
Robert P. J. Daydc041e02006-12-19 14:44:15 +01009384 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +01009385 if (spec == NULL)
9386 return -ENOMEM;
9387
9388 codec->spec = spec;
9389#if 0
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009390 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
9391 * under-run
9392 */
Kailang Yangdf694da2005-12-05 19:42:22 +01009393 {
9394 int tmp;
9395 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
9396 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
9397 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
9398 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
9399 }
9400#endif
9401
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009402 board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
9403 alc262_models,
9404 alc262_cfg_tbl);
Kailang Yangcd7509a2007-01-26 18:33:17 +01009405
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009406 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009407 printk(KERN_INFO "hda_codec: Unknown model for ALC262, "
9408 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01009409 board_config = ALC262_AUTO;
9410 }
9411
9412 if (board_config == ALC262_AUTO) {
9413 /* automatic parse from the BIOS config */
9414 err = alc262_parse_auto_config(codec);
9415 if (err < 0) {
9416 alc_free(codec);
9417 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009418 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009419 printk(KERN_INFO
9420 "hda_codec: Cannot set up configuration "
9421 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01009422 board_config = ALC262_BASIC;
9423 }
9424 }
9425
9426 if (board_config != ALC262_AUTO)
9427 setup_preset(spec, &alc262_presets[board_config]);
9428
9429 spec->stream_name_analog = "ALC262 Analog";
9430 spec->stream_analog_playback = &alc262_pcm_analog_playback;
9431 spec->stream_analog_capture = &alc262_pcm_analog_capture;
9432
9433 spec->stream_name_digital = "ALC262 Digital";
9434 spec->stream_digital_playback = &alc262_pcm_digital_playback;
9435 spec->stream_digital_capture = &alc262_pcm_digital_capture;
9436
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009437 if (!spec->adc_nids && spec->input_mux) {
Kailang Yangdf694da2005-12-05 19:42:22 +01009438 /* check whether NID 0x07 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +01009439 unsigned int wcap = get_wcaps(codec, 0x07);
9440
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009441 /* get type */
9442 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Kailang Yangdf694da2005-12-05 19:42:22 +01009443 if (wcap != AC_WID_AUD_IN) {
9444 spec->adc_nids = alc262_adc_nids_alt;
9445 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids_alt);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009446 spec->mixers[spec->num_mixers] =
9447 alc262_capture_alt_mixer;
Kailang Yangdf694da2005-12-05 19:42:22 +01009448 spec->num_mixers++;
9449 } else {
9450 spec->adc_nids = alc262_adc_nids;
9451 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids);
9452 spec->mixers[spec->num_mixers] = alc262_capture_mixer;
9453 spec->num_mixers++;
9454 }
9455 }
9456
Takashi Iwai2134ea42008-01-10 16:53:55 +01009457 spec->vmaster_nid = 0x0c;
9458
Kailang Yangdf694da2005-12-05 19:42:22 +01009459 codec->patch_ops = alc_patch_ops;
9460 if (board_config == ALC262_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01009461 spec->init_hook = alc262_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02009462#ifdef CONFIG_SND_HDA_POWER_SAVE
9463 if (!spec->loopback.amplist)
9464 spec->loopback.amplist = alc262_loopbacks;
9465#endif
Takashi Iwai834be882006-03-01 14:16:17 +01009466
Kailang Yangdf694da2005-12-05 19:42:22 +01009467 return 0;
9468}
9469
Kailang Yangdf694da2005-12-05 19:42:22 +01009470/*
Kailang Yanga361d842007-06-05 12:30:55 +02009471 * ALC268 channel source setting (2 channel)
9472 */
9473#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID
9474#define alc268_modes alc260_modes
9475
9476static hda_nid_t alc268_dac_nids[2] = {
9477 /* front, hp */
9478 0x02, 0x03
9479};
9480
9481static hda_nid_t alc268_adc_nids[2] = {
9482 /* ADC0-1 */
9483 0x08, 0x07
9484};
9485
9486static hda_nid_t alc268_adc_nids_alt[1] = {
9487 /* ADC0 */
9488 0x08
9489};
9490
Takashi Iwaie1406342008-02-11 18:32:32 +01009491static hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
9492
Kailang Yanga361d842007-06-05 12:30:55 +02009493static struct snd_kcontrol_new alc268_base_mixer[] = {
9494 /* output mixer control */
9495 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
9496 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9497 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
9498 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai33bf17a2007-08-21 11:51:42 +02009499 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9500 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
9501 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Kailang Yanga361d842007-06-05 12:30:55 +02009502 { }
9503};
9504
Kailang Yangd1a991a2007-08-15 16:21:59 +02009505static struct hda_verb alc268_eapd_verbs[] = {
9506 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
9507 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
9508 { }
9509};
9510
Takashi Iwaid2738092007-08-16 14:59:45 +02009511/* Toshiba specific */
9512#define alc268_toshiba_automute alc262_hippo_automute
9513
9514static struct hda_verb alc268_toshiba_verbs[] = {
9515 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9516 { } /* end */
9517};
9518
9519/* Acer specific */
Takashi Iwai889c4392007-08-23 18:56:52 +02009520/* bind volumes of both NID 0x02 and 0x03 */
Takashi Iwai6bc96852007-08-17 09:02:12 +02009521static struct hda_bind_ctls alc268_acer_bind_master_vol = {
9522 .ops = &snd_hda_bind_vol,
9523 .values = {
9524 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
9525 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
9526 0
9527 },
9528};
9529
Takashi Iwai889c4392007-08-23 18:56:52 +02009530/* mute/unmute internal speaker according to the hp jack and mute state */
9531static void alc268_acer_automute(struct hda_codec *codec, int force)
9532{
9533 struct alc_spec *spec = codec->spec;
9534 unsigned int mute;
9535
9536 if (force || !spec->sense_updated) {
9537 unsigned int present;
9538 present = snd_hda_codec_read(codec, 0x14, 0,
9539 AC_VERB_GET_PIN_SENSE, 0);
9540 spec->jack_present = (present & 0x80000000) != 0;
9541 spec->sense_updated = 1;
9542 }
9543 if (spec->jack_present)
9544 mute = HDA_AMP_MUTE; /* mute internal speaker */
9545 else /* unmute internal speaker if necessary */
9546 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
9547 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9548 HDA_AMP_MUTE, mute);
9549}
9550
9551
9552/* bind hp and internal speaker mute (with plug check) */
9553static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol,
9554 struct snd_ctl_elem_value *ucontrol)
9555{
9556 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9557 long *valp = ucontrol->value.integer.value;
9558 int change;
9559
9560 change = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
9561 HDA_AMP_MUTE,
9562 valp[0] ? 0 : HDA_AMP_MUTE);
9563 change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
9564 HDA_AMP_MUTE,
9565 valp[1] ? 0 : HDA_AMP_MUTE);
9566 if (change)
9567 alc268_acer_automute(codec, 0);
9568 return change;
9569}
Takashi Iwaid2738092007-08-16 14:59:45 +02009570
9571static struct snd_kcontrol_new alc268_acer_mixer[] = {
9572 /* output mixer control */
9573 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
9574 {
9575 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9576 .name = "Master Playback Switch",
9577 .info = snd_hda_mixer_amp_switch_info,
9578 .get = snd_hda_mixer_amp_switch_get,
9579 .put = alc268_acer_master_sw_put,
9580 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
9581 },
Takashi Iwai33bf17a2007-08-21 11:51:42 +02009582 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9583 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
9584 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Takashi Iwaid2738092007-08-16 14:59:45 +02009585 { }
9586};
9587
9588static struct hda_verb alc268_acer_verbs[] = {
9589 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9590 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9591
9592 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9593 { }
9594};
9595
9596/* unsolicited event for HP jack sensing */
9597static void alc268_toshiba_unsol_event(struct hda_codec *codec,
9598 unsigned int res)
9599{
Takashi Iwai889c4392007-08-23 18:56:52 +02009600 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +02009601 return;
9602 alc268_toshiba_automute(codec);
9603}
9604
9605static void alc268_acer_unsol_event(struct hda_codec *codec,
9606 unsigned int res)
9607{
Takashi Iwai889c4392007-08-23 18:56:52 +02009608 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +02009609 return;
9610 alc268_acer_automute(codec, 1);
9611}
9612
Takashi Iwai889c4392007-08-23 18:56:52 +02009613static void alc268_acer_init_hook(struct hda_codec *codec)
9614{
9615 alc268_acer_automute(codec, 1);
9616}
9617
Takashi Iwai3866f0b2008-01-15 12:37:42 +01009618static struct snd_kcontrol_new alc268_dell_mixer[] = {
9619 /* output mixer control */
9620 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
9621 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9622 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
9623 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9624 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9625 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
9626 { }
9627};
9628
9629static struct hda_verb alc268_dell_verbs[] = {
9630 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9631 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9632 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9633 { }
9634};
9635
9636/* mute/unmute internal speaker according to the hp jack and mute state */
9637static void alc268_dell_automute(struct hda_codec *codec)
9638{
9639 unsigned int present;
9640 unsigned int mute;
9641
9642 present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0);
9643 if (present & 0x80000000)
9644 mute = HDA_AMP_MUTE;
9645 else
9646 mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
9647 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9648 HDA_AMP_MUTE, mute);
9649}
9650
9651static void alc268_dell_unsol_event(struct hda_codec *codec,
9652 unsigned int res)
9653{
9654 if ((res >> 26) != ALC880_HP_EVENT)
9655 return;
9656 alc268_dell_automute(codec);
9657}
9658
9659#define alc268_dell_init_hook alc268_dell_automute
9660
Kailang Yanga361d842007-06-05 12:30:55 +02009661/*
9662 * generic initialization of ADC, input mixers and output mixers
9663 */
9664static struct hda_verb alc268_base_init_verbs[] = {
9665 /* Unmute DAC0-1 and set vol = 0 */
9666 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9667 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9668 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9669 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9670 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9671 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9672
9673 /*
9674 * Set up output mixers (0x0c - 0x0e)
9675 */
9676 /* set vol=0 to output mixers */
9677 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9678 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9679 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9680 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
9681
9682 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9683 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9684
9685 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
9686 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
9687 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
9688 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9689 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9690 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9691 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9692 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9693
9694 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9695 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9696 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9697 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9698 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9699 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9700 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9701 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9702
Jiang Zhea9b3aa82007-12-20 13:13:13 +01009703 /* Unmute Selector 23h,24h and set the default input to mic-in */
9704
9705 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
9706 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9707 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
9708 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yanga361d842007-06-05 12:30:55 +02009709
Kailang Yanga361d842007-06-05 12:30:55 +02009710 { }
9711};
9712
9713/*
9714 * generic initialization of ADC, input mixers and output mixers
9715 */
9716static struct hda_verb alc268_volume_init_verbs[] = {
9717 /* set output DAC */
9718 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9719 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9720 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9721 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9722
9723 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9724 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9725 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9726 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9727 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9728
9729 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9730 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9731 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9732 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9733 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9734
9735 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9736 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9737 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9738 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9739
9740 /* set PCBEEP vol = 0 */
9741 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, (0xb000 | (0x00 << 8))},
9742
9743 { }
9744};
9745
9746#define alc268_mux_enum_info alc_mux_enum_info
9747#define alc268_mux_enum_get alc_mux_enum_get
Takashi Iwaie1406342008-02-11 18:32:32 +01009748#define alc268_mux_enum_put alc_mux_enum_put
Kailang Yanga361d842007-06-05 12:30:55 +02009749
9750static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
9751 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
9752 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
9753 {
9754 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9755 /* The multiple "Capture Source" controls confuse alsamixer
9756 * So call somewhat different..
Kailang Yanga361d842007-06-05 12:30:55 +02009757 */
9758 /* .name = "Capture Source", */
9759 .name = "Input Source",
9760 .count = 1,
9761 .info = alc268_mux_enum_info,
9762 .get = alc268_mux_enum_get,
9763 .put = alc268_mux_enum_put,
9764 },
9765 { } /* end */
9766};
9767
9768static struct snd_kcontrol_new alc268_capture_mixer[] = {
9769 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
9770 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
9771 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
9772 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
9773 {
9774 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9775 /* The multiple "Capture Source" controls confuse alsamixer
9776 * So call somewhat different..
Kailang Yanga361d842007-06-05 12:30:55 +02009777 */
9778 /* .name = "Capture Source", */
9779 .name = "Input Source",
9780 .count = 2,
9781 .info = alc268_mux_enum_info,
9782 .get = alc268_mux_enum_get,
9783 .put = alc268_mux_enum_put,
9784 },
9785 { } /* end */
9786};
9787
9788static struct hda_input_mux alc268_capture_source = {
9789 .num_items = 4,
9790 .items = {
9791 { "Mic", 0x0 },
9792 { "Front Mic", 0x1 },
9793 { "Line", 0x2 },
9794 { "CD", 0x3 },
9795 },
9796};
9797
Jonathan Woithe86c53bd2008-01-08 12:33:19 +01009798#ifdef CONFIG_SND_DEBUG
9799static struct snd_kcontrol_new alc268_test_mixer[] = {
Jonathan Woithe86c53bd2008-01-08 12:33:19 +01009800 /* Volume widgets */
9801 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
9802 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
9803 HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
9804 HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
9805 HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
9806 HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
9807 HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
9808 HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
9809 HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
9810 HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
9811 HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
9812 HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
9813 HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
Takashi Iwaif0747ee2008-01-15 11:41:41 +01009814 /* The below appears problematic on some hardwares */
9815 /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
Jonathan Woithe86c53bd2008-01-08 12:33:19 +01009816 HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
9817 HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
9818 HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
9819 HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
9820
9821 /* Modes for retasking pin widgets */
9822 ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
9823 ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
9824 ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
9825 ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
9826
9827 /* Controls for GPIO pins, assuming they are configured as outputs */
9828 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
9829 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
9830 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
9831 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
9832
9833 /* Switches to allow the digital SPDIF output pin to be enabled.
9834 * The ALC268 does not have an SPDIF input.
9835 */
9836 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
9837
9838 /* A switch allowing EAPD to be enabled. Some laptops seem to use
9839 * this output to turn on an external amplifier.
9840 */
9841 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
9842 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
9843
9844 { } /* end */
9845};
9846#endif
9847
Kailang Yanga361d842007-06-05 12:30:55 +02009848/* create input playback/capture controls for the given pin */
9849static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
9850 const char *ctlname, int idx)
9851{
9852 char name[32];
9853 int err;
9854
9855 sprintf(name, "%s Playback Volume", ctlname);
9856 if (nid == 0x14) {
9857 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
9858 HDA_COMPOSE_AMP_VAL(0x02, 3, idx,
9859 HDA_OUTPUT));
9860 if (err < 0)
9861 return err;
9862 } else if (nid == 0x15) {
9863 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
9864 HDA_COMPOSE_AMP_VAL(0x03, 3, idx,
9865 HDA_OUTPUT));
9866 if (err < 0)
9867 return err;
9868 } else
9869 return -1;
9870 sprintf(name, "%s Playback Switch", ctlname);
9871 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
9872 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
9873 if (err < 0)
9874 return err;
9875 return 0;
9876}
9877
9878/* add playback controls from the parsed DAC table */
9879static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
9880 const struct auto_pin_cfg *cfg)
9881{
9882 hda_nid_t nid;
9883 int err;
9884
9885 spec->multiout.num_dacs = 2; /* only use one dac */
9886 spec->multiout.dac_nids = spec->private_dac_nids;
9887 spec->multiout.dac_nids[0] = 2;
9888 spec->multiout.dac_nids[1] = 3;
9889
9890 nid = cfg->line_out_pins[0];
9891 if (nid)
9892 alc268_new_analog_output(spec, nid, "Front", 0);
9893
9894 nid = cfg->speaker_pins[0];
9895 if (nid == 0x1d) {
9896 err = add_control(spec, ALC_CTL_WIDGET_VOL,
9897 "Speaker Playback Volume",
9898 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
9899 if (err < 0)
9900 return err;
9901 }
9902 nid = cfg->hp_pins[0];
9903 if (nid)
9904 alc268_new_analog_output(spec, nid, "Headphone", 0);
9905
9906 nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
9907 if (nid == 0x16) {
9908 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9909 "Mono Playback Switch",
9910 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_INPUT));
9911 if (err < 0)
9912 return err;
9913 }
9914 return 0;
9915}
9916
9917/* create playback/capture controls for input pins */
9918static int alc268_auto_create_analog_input_ctls(struct alc_spec *spec,
9919 const struct auto_pin_cfg *cfg)
9920{
9921 struct hda_input_mux *imux = &spec->private_imux;
9922 int i, idx1;
9923
9924 for (i = 0; i < AUTO_PIN_LAST; i++) {
9925 switch(cfg->input_pins[i]) {
9926 case 0x18:
9927 idx1 = 0; /* Mic 1 */
9928 break;
9929 case 0x19:
9930 idx1 = 1; /* Mic 2 */
9931 break;
9932 case 0x1a:
9933 idx1 = 2; /* Line In */
9934 break;
9935 case 0x1c:
9936 idx1 = 3; /* CD */
9937 break;
9938 default:
9939 continue;
9940 }
9941 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
9942 imux->items[imux->num_items].index = idx1;
9943 imux->num_items++;
9944 }
9945 return 0;
9946}
9947
9948static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
9949{
9950 struct alc_spec *spec = codec->spec;
9951 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
9952 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
9953 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
9954 unsigned int dac_vol1, dac_vol2;
9955
9956 if (speaker_nid) {
9957 snd_hda_codec_write(codec, speaker_nid, 0,
9958 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
9959 snd_hda_codec_write(codec, 0x0f, 0,
9960 AC_VERB_SET_AMP_GAIN_MUTE,
9961 AMP_IN_UNMUTE(1));
9962 snd_hda_codec_write(codec, 0x10, 0,
9963 AC_VERB_SET_AMP_GAIN_MUTE,
9964 AMP_IN_UNMUTE(1));
9965 } else {
9966 snd_hda_codec_write(codec, 0x0f, 0,
9967 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
9968 snd_hda_codec_write(codec, 0x10, 0,
9969 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
9970 }
9971
9972 dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */
9973 if (line_nid == 0x14)
9974 dac_vol2 = AMP_OUT_ZERO;
9975 else if (line_nid == 0x15)
9976 dac_vol1 = AMP_OUT_ZERO;
9977 if (hp_nid == 0x14)
9978 dac_vol2 = AMP_OUT_ZERO;
9979 else if (hp_nid == 0x15)
9980 dac_vol1 = AMP_OUT_ZERO;
9981 if (line_nid != 0x16 || hp_nid != 0x16 ||
9982 spec->autocfg.line_out_pins[1] != 0x16 ||
9983 spec->autocfg.line_out_pins[2] != 0x16)
9984 dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
9985
9986 snd_hda_codec_write(codec, 0x02, 0,
9987 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
9988 snd_hda_codec_write(codec, 0x03, 0,
9989 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
9990}
9991
9992/* pcm configuration: identiacal with ALC880 */
9993#define alc268_pcm_analog_playback alc880_pcm_analog_playback
9994#define alc268_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +01009995#define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Kailang Yanga361d842007-06-05 12:30:55 +02009996#define alc268_pcm_digital_playback alc880_pcm_digital_playback
9997
9998/*
9999 * BIOS auto configuration
10000 */
10001static int alc268_parse_auto_config(struct hda_codec *codec)
10002{
10003 struct alc_spec *spec = codec->spec;
10004 int err;
10005 static hda_nid_t alc268_ignore[] = { 0 };
10006
10007 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
10008 alc268_ignore);
10009 if (err < 0)
10010 return err;
10011 if (!spec->autocfg.line_outs)
10012 return 0; /* can't find valid BIOS pin config */
10013
10014 err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
10015 if (err < 0)
10016 return err;
10017 err = alc268_auto_create_analog_input_ctls(spec, &spec->autocfg);
10018 if (err < 0)
10019 return err;
10020
10021 spec->multiout.max_channels = 2;
10022
10023 /* digital only support output */
10024 if (spec->autocfg.dig_out_pin)
10025 spec->multiout.dig_out_nid = ALC268_DIGOUT_NID;
10026
10027 if (spec->kctl_alloc)
10028 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
10029
10030 spec->init_verbs[spec->num_init_verbs++] = alc268_volume_init_verbs;
10031 spec->num_mux_defs = 1;
10032 spec->input_mux = &spec->private_imux;
10033
Takashi Iwai776e1842007-08-29 15:07:11 +020010034 err = alc_auto_add_mic_boost(codec);
10035 if (err < 0)
10036 return err;
10037
Kailang Yanga361d842007-06-05 12:30:55 +020010038 return 1;
10039}
10040
10041#define alc268_auto_init_multi_out alc882_auto_init_multi_out
10042#define alc268_auto_init_hp_out alc882_auto_init_hp_out
10043#define alc268_auto_init_analog_input alc882_auto_init_analog_input
10044
10045/* init callback for auto-configuration model -- overriding the default init */
10046static void alc268_auto_init(struct hda_codec *codec)
10047{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010048 struct alc_spec *spec = codec->spec;
Kailang Yanga361d842007-06-05 12:30:55 +020010049 alc268_auto_init_multi_out(codec);
10050 alc268_auto_init_hp_out(codec);
10051 alc268_auto_init_mono_speaker_out(codec);
10052 alc268_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010053 if (spec->unsol_event)
10054 alc_sku_automute(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020010055}
10056
10057/*
10058 * configuration and preset
10059 */
10060static const char *alc268_models[ALC268_MODEL_LAST] = {
10061 [ALC268_3ST] = "3stack",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020010062 [ALC268_TOSHIBA] = "toshiba",
Takashi Iwaid2738092007-08-16 14:59:45 +020010063 [ALC268_ACER] = "acer",
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010064 [ALC268_DELL] = "dell",
Mirco Tischlerf12462c2008-02-04 12:33:59 +010010065 [ALC268_ZEPTO] = "zepto",
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010010066#ifdef CONFIG_SND_DEBUG
10067 [ALC268_TEST] = "test",
10068#endif
Kailang Yanga361d842007-06-05 12:30:55 +020010069 [ALC268_AUTO] = "auto",
10070};
10071
10072static struct snd_pci_quirk alc268_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010073 SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
Andy Shevchenkodafc8352008-01-25 11:53:50 +010010074 SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010075 SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
Andy Shevchenko29a52c22008-01-24 17:29:00 +010010076 SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010077 SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010078 SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA),
Kailang Yanga361d842007-06-05 12:30:55 +020010079 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
Kailang Yangd1a991a2007-08-15 16:21:59 +020010080 SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA),
Takashi Iwai8e7f00f2007-09-07 10:58:58 +020010081 SND_PCI_QUIRK(0x1179, 0xff50, "TOSHIBA A305", ALC268_TOSHIBA),
Takashi Iwaib875bf32007-09-06 15:00:27 +020010082 SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
Mirco Tischlerf12462c2008-02-04 12:33:59 +010010083 SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
Kailang Yanga361d842007-06-05 12:30:55 +020010084 {}
10085};
10086
10087static struct alc_config_preset alc268_presets[] = {
10088 [ALC268_3ST] = {
10089 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer },
10090 .init_verbs = { alc268_base_init_verbs },
10091 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
10092 .dac_nids = alc268_dac_nids,
10093 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
10094 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010010095 .capsrc_nids = alc268_capsrc_nids,
Kailang Yanga361d842007-06-05 12:30:55 +020010096 .hp_nid = 0x03,
10097 .dig_out_nid = ALC268_DIGOUT_NID,
10098 .num_channel_mode = ARRAY_SIZE(alc268_modes),
10099 .channel_mode = alc268_modes,
10100 .input_mux = &alc268_capture_source,
10101 },
Kailang Yangd1a991a2007-08-15 16:21:59 +020010102 [ALC268_TOSHIBA] = {
10103 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020010104 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
10105 alc268_toshiba_verbs },
Kailang Yangd1a991a2007-08-15 16:21:59 +020010106 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
10107 .dac_nids = alc268_dac_nids,
10108 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
10109 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010010110 .capsrc_nids = alc268_capsrc_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020010111 .hp_nid = 0x03,
10112 .num_channel_mode = ARRAY_SIZE(alc268_modes),
10113 .channel_mode = alc268_modes,
10114 .input_mux = &alc268_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020010115 .unsol_event = alc268_toshiba_unsol_event,
10116 .init_hook = alc268_toshiba_automute,
10117 },
10118 [ALC268_ACER] = {
10119 .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer },
10120 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
10121 alc268_acer_verbs },
10122 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
10123 .dac_nids = alc268_dac_nids,
10124 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
10125 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010010126 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwaid2738092007-08-16 14:59:45 +020010127 .hp_nid = 0x02,
10128 .num_channel_mode = ARRAY_SIZE(alc268_modes),
10129 .channel_mode = alc268_modes,
10130 .input_mux = &alc268_capture_source,
10131 .unsol_event = alc268_acer_unsol_event,
Takashi Iwai889c4392007-08-23 18:56:52 +020010132 .init_hook = alc268_acer_init_hook,
Kailang Yangd1a991a2007-08-15 16:21:59 +020010133 },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010134 [ALC268_DELL] = {
10135 .mixers = { alc268_dell_mixer },
10136 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
10137 alc268_dell_verbs },
10138 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
10139 .dac_nids = alc268_dac_nids,
10140 .hp_nid = 0x02,
10141 .num_channel_mode = ARRAY_SIZE(alc268_modes),
10142 .channel_mode = alc268_modes,
10143 .unsol_event = alc268_dell_unsol_event,
10144 .init_hook = alc268_dell_init_hook,
10145 .input_mux = &alc268_capture_source,
10146 },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010010147 [ALC268_ZEPTO] = {
10148 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer },
10149 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
10150 alc268_toshiba_verbs },
10151 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
10152 .dac_nids = alc268_dac_nids,
10153 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
10154 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010010155 .capsrc_nids = alc268_capsrc_nids,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010010156 .hp_nid = 0x03,
10157 .dig_out_nid = ALC268_DIGOUT_NID,
10158 .num_channel_mode = ARRAY_SIZE(alc268_modes),
10159 .channel_mode = alc268_modes,
10160 .input_mux = &alc268_capture_source,
10161 .unsol_event = alc268_toshiba_unsol_event,
10162 .init_hook = alc268_toshiba_automute
10163 },
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010010164#ifdef CONFIG_SND_DEBUG
10165 [ALC268_TEST] = {
10166 .mixers = { alc268_test_mixer, alc268_capture_mixer },
10167 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
10168 alc268_volume_init_verbs },
10169 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
10170 .dac_nids = alc268_dac_nids,
10171 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
10172 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010010173 .capsrc_nids = alc268_capsrc_nids,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010010174 .hp_nid = 0x03,
10175 .dig_out_nid = ALC268_DIGOUT_NID,
10176 .num_channel_mode = ARRAY_SIZE(alc268_modes),
10177 .channel_mode = alc268_modes,
10178 .input_mux = &alc268_capture_source,
10179 },
10180#endif
Kailang Yanga361d842007-06-05 12:30:55 +020010181};
10182
10183static int patch_alc268(struct hda_codec *codec)
10184{
10185 struct alc_spec *spec;
10186 int board_config;
10187 int err;
10188
10189 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
10190 if (spec == NULL)
10191 return -ENOMEM;
10192
10193 codec->spec = spec;
10194
10195 board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
10196 alc268_models,
10197 alc268_cfg_tbl);
10198
10199 if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
10200 printk(KERN_INFO "hda_codec: Unknown model for ALC268, "
10201 "trying auto-probe from BIOS...\n");
10202 board_config = ALC268_AUTO;
10203 }
10204
10205 if (board_config == ALC268_AUTO) {
10206 /* automatic parse from the BIOS config */
10207 err = alc268_parse_auto_config(codec);
10208 if (err < 0) {
10209 alc_free(codec);
10210 return err;
10211 } else if (!err) {
10212 printk(KERN_INFO
10213 "hda_codec: Cannot set up configuration "
10214 "from BIOS. Using base mode...\n");
10215 board_config = ALC268_3ST;
10216 }
10217 }
10218
10219 if (board_config != ALC268_AUTO)
10220 setup_preset(spec, &alc268_presets[board_config]);
10221
10222 spec->stream_name_analog = "ALC268 Analog";
10223 spec->stream_analog_playback = &alc268_pcm_analog_playback;
10224 spec->stream_analog_capture = &alc268_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +010010225 spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
Kailang Yanga361d842007-06-05 12:30:55 +020010226
10227 spec->stream_name_digital = "ALC268 Digital";
10228 spec->stream_digital_playback = &alc268_pcm_digital_playback;
10229
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010230 if (!spec->adc_nids && spec->input_mux) {
10231 /* check whether NID 0x07 is valid */
10232 unsigned int wcap = get_wcaps(codec, 0x07);
Kailang Yanga361d842007-06-05 12:30:55 +020010233
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010234 /* get type */
10235 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
10236 if (wcap != AC_WID_AUD_IN) {
10237 spec->adc_nids = alc268_adc_nids_alt;
10238 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
10239 spec->mixers[spec->num_mixers] =
Kailang Yanga361d842007-06-05 12:30:55 +020010240 alc268_capture_alt_mixer;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010241 spec->num_mixers++;
10242 } else {
10243 spec->adc_nids = alc268_adc_nids;
10244 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
10245 spec->mixers[spec->num_mixers] =
10246 alc268_capture_mixer;
10247 spec->num_mixers++;
Kailang Yanga361d842007-06-05 12:30:55 +020010248 }
Takashi Iwaie1406342008-02-11 18:32:32 +010010249 spec->capsrc_nids = alc268_capsrc_nids;
Kailang Yanga361d842007-06-05 12:30:55 +020010250 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010010251
10252 spec->vmaster_nid = 0x02;
10253
Kailang Yanga361d842007-06-05 12:30:55 +020010254 codec->patch_ops = alc_patch_ops;
10255 if (board_config == ALC268_AUTO)
10256 spec->init_hook = alc268_auto_init;
10257
10258 return 0;
10259}
10260
10261/*
Kailang Yangf6a92242007-12-13 16:52:54 +010010262 * ALC269 channel source setting (2 channel)
10263 */
10264#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID
10265
10266#define alc269_dac_nids alc260_dac_nids
10267
10268static hda_nid_t alc269_adc_nids[1] = {
10269 /* ADC1 */
10270 0x07,
10271};
10272
10273#define alc269_modes alc260_modes
10274#define alc269_capture_source alc880_lg_lw_capture_source
10275
10276static struct snd_kcontrol_new alc269_base_mixer[] = {
10277 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
10278 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
10279 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
10280 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
10281 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10282 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10283 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10284 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10285 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
10286 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
10287 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10288 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
10289 { } /* end */
10290};
10291
10292/* capture mixer elements */
10293static struct snd_kcontrol_new alc269_capture_mixer[] = {
10294 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
10295 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
10296 {
10297 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10298 /* The multiple "Capture Source" controls confuse alsamixer
10299 * So call somewhat different..
Kailang Yangf6a92242007-12-13 16:52:54 +010010300 */
10301 /* .name = "Capture Source", */
10302 .name = "Input Source",
10303 .count = 1,
10304 .info = alc_mux_enum_info,
10305 .get = alc_mux_enum_get,
10306 .put = alc_mux_enum_put,
10307 },
10308 { } /* end */
10309};
10310
10311/*
10312 * generic initialization of ADC, input mixers and output mixers
10313 */
10314static struct hda_verb alc269_init_verbs[] = {
10315 /*
10316 * Unmute ADC0 and set the default input to mic-in
10317 */
10318 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10319
10320 /* Mute input amps (PCBeep, Line In, Mic 1 & Mic 2) of the
10321 * analog-loopback mixer widget
10322 * Note: PASD motherboards uses the Line In 2 as the input for
10323 * front panel mic (mic 2)
10324 */
10325 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
10326 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10327 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10328 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10329 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10330 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
10331
10332 /*
10333 * Set up output mixers (0x0c - 0x0e)
10334 */
10335 /* set vol=0 to output mixers */
10336 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10337 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10338
10339 /* set up input amps for analog loopback */
10340 /* Amp Indices: DAC = 0, mixer = 1 */
10341 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10342 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10343 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10344 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10345 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10346 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10347
10348 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10349 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10350 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10351 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
10352 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
10353 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
10354 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
10355
10356 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10357 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10358 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10359 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10360 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10361 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10362 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10363
10364 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
10365 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10366
10367 /* FIXME: use matrix-type input source selection */
10368 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
10369 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
10370 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10371 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10372 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10373 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10374
10375 /* set EAPD */
10376 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
10377 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
10378 { }
10379};
10380
10381/* add playback controls from the parsed DAC table */
10382static int alc269_auto_create_multi_out_ctls(struct alc_spec *spec,
10383 const struct auto_pin_cfg *cfg)
10384{
10385 hda_nid_t nid;
10386 int err;
10387
10388 spec->multiout.num_dacs = 1; /* only use one dac */
10389 spec->multiout.dac_nids = spec->private_dac_nids;
10390 spec->multiout.dac_nids[0] = 2;
10391
10392 nid = cfg->line_out_pins[0];
10393 if (nid) {
10394 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10395 "Front Playback Volume",
10396 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT));
10397 if (err < 0)
10398 return err;
10399 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10400 "Front Playback Switch",
10401 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
10402 if (err < 0)
10403 return err;
10404 }
10405
10406 nid = cfg->speaker_pins[0];
10407 if (nid) {
10408 if (!cfg->line_out_pins[0]) {
10409 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10410 "Speaker Playback Volume",
10411 HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
10412 HDA_OUTPUT));
10413 if (err < 0)
10414 return err;
10415 }
10416 if (nid == 0x16) {
10417 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10418 "Speaker Playback Switch",
10419 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
10420 HDA_OUTPUT));
10421 if (err < 0)
10422 return err;
10423 } else {
10424 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10425 "Speaker Playback Switch",
10426 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
10427 HDA_OUTPUT));
10428 if (err < 0)
10429 return err;
10430 }
10431 }
10432 nid = cfg->hp_pins[0];
10433 if (nid) {
10434 /* spec->multiout.hp_nid = 2; */
10435 if (!cfg->line_out_pins[0] && !cfg->speaker_pins[0]) {
10436 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10437 "Headphone Playback Volume",
10438 HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
10439 HDA_OUTPUT));
10440 if (err < 0)
10441 return err;
10442 }
10443 if (nid == 0x16) {
10444 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10445 "Headphone Playback Switch",
10446 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
10447 HDA_OUTPUT));
10448 if (err < 0)
10449 return err;
10450 } else {
10451 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10452 "Headphone Playback Switch",
10453 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
10454 HDA_OUTPUT));
10455 if (err < 0)
10456 return err;
10457 }
10458 }
10459 return 0;
10460}
10461
10462#define alc269_auto_create_analog_input_ctls \
10463 alc880_auto_create_analog_input_ctls
10464
10465#ifdef CONFIG_SND_HDA_POWER_SAVE
10466#define alc269_loopbacks alc880_loopbacks
10467#endif
10468
10469/* pcm configuration: identiacal with ALC880 */
10470#define alc269_pcm_analog_playback alc880_pcm_analog_playback
10471#define alc269_pcm_analog_capture alc880_pcm_analog_capture
10472#define alc269_pcm_digital_playback alc880_pcm_digital_playback
10473#define alc269_pcm_digital_capture alc880_pcm_digital_capture
10474
10475/*
10476 * BIOS auto configuration
10477 */
10478static int alc269_parse_auto_config(struct hda_codec *codec)
10479{
10480 struct alc_spec *spec = codec->spec;
10481 int err;
10482 static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
10483
10484 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
10485 alc269_ignore);
10486 if (err < 0)
10487 return err;
10488
10489 err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
10490 if (err < 0)
10491 return err;
10492 err = alc269_auto_create_analog_input_ctls(spec, &spec->autocfg);
10493 if (err < 0)
10494 return err;
10495
10496 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
10497
10498 if (spec->autocfg.dig_out_pin)
10499 spec->multiout.dig_out_nid = ALC269_DIGOUT_NID;
10500
10501 if (spec->kctl_alloc)
10502 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
10503
10504 spec->init_verbs[spec->num_init_verbs++] = alc269_init_verbs;
10505 spec->num_mux_defs = 1;
10506 spec->input_mux = &spec->private_imux;
10507
10508 err = alc_auto_add_mic_boost(codec);
10509 if (err < 0)
10510 return err;
10511
10512 return 1;
10513}
10514
10515#define alc269_auto_init_multi_out alc882_auto_init_multi_out
10516#define alc269_auto_init_hp_out alc882_auto_init_hp_out
10517#define alc269_auto_init_analog_input alc882_auto_init_analog_input
10518
10519
10520/* init callback for auto-configuration model -- overriding the default init */
10521static void alc269_auto_init(struct hda_codec *codec)
10522{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010523 struct alc_spec *spec = codec->spec;
Kailang Yangf6a92242007-12-13 16:52:54 +010010524 alc269_auto_init_multi_out(codec);
10525 alc269_auto_init_hp_out(codec);
10526 alc269_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010527 if (spec->unsol_event)
10528 alc_sku_automute(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010010529}
10530
10531/*
10532 * configuration and preset
10533 */
10534static const char *alc269_models[ALC269_MODEL_LAST] = {
10535 [ALC269_BASIC] = "basic",
10536};
10537
10538static struct snd_pci_quirk alc269_cfg_tbl[] = {
10539 {}
10540};
10541
10542static struct alc_config_preset alc269_presets[] = {
10543 [ALC269_BASIC] = {
10544 .mixers = { alc269_base_mixer },
10545 .init_verbs = { alc269_init_verbs },
10546 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
10547 .dac_nids = alc269_dac_nids,
10548 .hp_nid = 0x03,
10549 .num_channel_mode = ARRAY_SIZE(alc269_modes),
10550 .channel_mode = alc269_modes,
10551 .input_mux = &alc269_capture_source,
10552 },
10553};
10554
10555static int patch_alc269(struct hda_codec *codec)
10556{
10557 struct alc_spec *spec;
10558 int board_config;
10559 int err;
10560
10561 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
10562 if (spec == NULL)
10563 return -ENOMEM;
10564
10565 codec->spec = spec;
10566
10567 board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
10568 alc269_models,
10569 alc269_cfg_tbl);
10570
10571 if (board_config < 0) {
10572 printk(KERN_INFO "hda_codec: Unknown model for ALC269, "
10573 "trying auto-probe from BIOS...\n");
10574 board_config = ALC269_AUTO;
10575 }
10576
10577 if (board_config == ALC269_AUTO) {
10578 /* automatic parse from the BIOS config */
10579 err = alc269_parse_auto_config(codec);
10580 if (err < 0) {
10581 alc_free(codec);
10582 return err;
10583 } else if (!err) {
10584 printk(KERN_INFO
10585 "hda_codec: Cannot set up configuration "
10586 "from BIOS. Using base mode...\n");
10587 board_config = ALC269_BASIC;
10588 }
10589 }
10590
10591 if (board_config != ALC269_AUTO)
10592 setup_preset(spec, &alc269_presets[board_config]);
10593
10594 spec->stream_name_analog = "ALC269 Analog";
10595 spec->stream_analog_playback = &alc269_pcm_analog_playback;
10596 spec->stream_analog_capture = &alc269_pcm_analog_capture;
10597
10598 spec->stream_name_digital = "ALC269 Digital";
10599 spec->stream_digital_playback = &alc269_pcm_digital_playback;
10600 spec->stream_digital_capture = &alc269_pcm_digital_capture;
10601
10602 spec->adc_nids = alc269_adc_nids;
10603 spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
10604 spec->mixers[spec->num_mixers] = alc269_capture_mixer;
10605 spec->num_mixers++;
10606
10607 codec->patch_ops = alc_patch_ops;
10608 if (board_config == ALC269_AUTO)
10609 spec->init_hook = alc269_auto_init;
10610#ifdef CONFIG_SND_HDA_POWER_SAVE
10611 if (!spec->loopback.amplist)
10612 spec->loopback.amplist = alc269_loopbacks;
10613#endif
10614
10615 return 0;
10616}
10617
10618/*
Kailang Yangdf694da2005-12-05 19:42:22 +010010619 * ALC861 channel source setting (2/6 channel selection for 3-stack)
10620 */
10621
10622/*
10623 * set the path ways for 2 channel output
10624 * need to set the codec line out and mic 1 pin widgets to inputs
10625 */
10626static struct hda_verb alc861_threestack_ch2_init[] = {
10627 /* set pin widget 1Ah (line in) for input */
10628 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010629 /* set pin widget 18h (mic1/2) for input, for mic also enable
10630 * the vref
10631 */
Kailang Yangdf694da2005-12-05 19:42:22 +010010632 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10633
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010634 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
10635#if 0
10636 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
10637 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
10638#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010010639 { } /* end */
10640};
10641/*
10642 * 6ch mode
10643 * need to set the codec line out and mic 1 pin widgets to outputs
10644 */
10645static struct hda_verb alc861_threestack_ch6_init[] = {
10646 /* set pin widget 1Ah (line in) for output (Back Surround)*/
10647 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10648 /* set pin widget 18h (mic1) for output (CLFE)*/
10649 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10650
10651 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010652 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010010653
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010654 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
10655#if 0
10656 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
10657 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
10658#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010010659 { } /* end */
10660};
10661
10662static struct hda_channel_mode alc861_threestack_modes[2] = {
10663 { 2, alc861_threestack_ch2_init },
10664 { 6, alc861_threestack_ch6_init },
10665};
Takashi Iwai22309c32006-08-09 16:57:28 +020010666/* Set mic1 as input and unmute the mixer */
10667static struct hda_verb alc861_uniwill_m31_ch2_init[] = {
10668 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10669 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
10670 { } /* end */
10671};
10672/* Set mic1 as output and mute mixer */
10673static struct hda_verb alc861_uniwill_m31_ch4_init[] = {
10674 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10675 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
10676 { } /* end */
10677};
10678
10679static struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
10680 { 2, alc861_uniwill_m31_ch2_init },
10681 { 4, alc861_uniwill_m31_ch4_init },
10682};
Kailang Yangdf694da2005-12-05 19:42:22 +010010683
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020010684/* Set mic1 and line-in as input and unmute the mixer */
10685static struct hda_verb alc861_asus_ch2_init[] = {
10686 /* set pin widget 1Ah (line in) for input */
10687 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010688 /* set pin widget 18h (mic1/2) for input, for mic also enable
10689 * the vref
10690 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020010691 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10692
10693 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
10694#if 0
10695 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
10696 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
10697#endif
10698 { } /* end */
10699};
10700/* Set mic1 nad line-in as output and mute mixer */
10701static struct hda_verb alc861_asus_ch6_init[] = {
10702 /* set pin widget 1Ah (line in) for output (Back Surround)*/
10703 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10704 /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
10705 /* set pin widget 18h (mic1) for output (CLFE)*/
10706 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10707 /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
10708 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
10709 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
10710
10711 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
10712#if 0
10713 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
10714 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
10715#endif
10716 { } /* end */
10717};
10718
10719static struct hda_channel_mode alc861_asus_modes[2] = {
10720 { 2, alc861_asus_ch2_init },
10721 { 6, alc861_asus_ch6_init },
10722};
10723
Kailang Yangdf694da2005-12-05 19:42:22 +010010724/* patch-ALC861 */
10725
10726static struct snd_kcontrol_new alc861_base_mixer[] = {
10727 /* output mixer control */
10728 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
10729 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
10730 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
10731 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
10732 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
10733
10734 /*Input mixer control */
10735 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
10736 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
10737 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
10738 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
10739 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
10740 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
10741 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
10742 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
10743 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
10744 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010745
Kailang Yangdf694da2005-12-05 19:42:22 +010010746 /* Capture mixer control */
10747 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
10748 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
10749 {
10750 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10751 .name = "Capture Source",
10752 .count = 1,
10753 .info = alc_mux_enum_info,
10754 .get = alc_mux_enum_get,
10755 .put = alc_mux_enum_put,
10756 },
10757 { } /* end */
10758};
10759
10760static struct snd_kcontrol_new alc861_3ST_mixer[] = {
10761 /* output mixer control */
10762 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
10763 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
10764 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
10765 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
10766 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
10767
10768 /* Input mixer control */
10769 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
10770 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
10771 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
10772 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
10773 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
10774 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
10775 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
10776 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
10777 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
10778 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010779
Kailang Yangdf694da2005-12-05 19:42:22 +010010780 /* Capture mixer control */
10781 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
10782 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
10783 {
10784 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10785 .name = "Capture Source",
10786 .count = 1,
10787 .info = alc_mux_enum_info,
10788 .get = alc_mux_enum_get,
10789 .put = alc_mux_enum_put,
10790 },
10791 {
10792 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10793 .name = "Channel Mode",
10794 .info = alc_ch_mode_info,
10795 .get = alc_ch_mode_get,
10796 .put = alc_ch_mode_put,
10797 .private_value = ARRAY_SIZE(alc861_threestack_modes),
10798 },
10799 { } /* end */
Tobin Davisa53d1ae2006-10-17 12:00:28 +020010800};
10801
Takashi Iwaid1d985f2006-11-23 19:27:12 +010010802static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020010803 /* output mixer control */
10804 HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
10805 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
10806 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
10807
10808 /*Capture mixer control */
10809 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
10810 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
10811 {
10812 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10813 .name = "Capture Source",
10814 .count = 1,
10815 .info = alc_mux_enum_info,
10816 .get = alc_mux_enum_get,
10817 .put = alc_mux_enum_put,
10818 },
10819
10820 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010821};
Tobin Davisa53d1ae2006-10-17 12:00:28 +020010822
Takashi Iwai22309c32006-08-09 16:57:28 +020010823static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
10824 /* output mixer control */
10825 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
10826 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
10827 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
10828 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
10829 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
10830
10831 /* Input mixer control */
10832 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
10833 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
10834 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
10835 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
10836 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
10837 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
10838 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
10839 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
10840 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
10841 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010842
Takashi Iwai22309c32006-08-09 16:57:28 +020010843 /* Capture mixer control */
10844 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
10845 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
10846 {
10847 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10848 .name = "Capture Source",
10849 .count = 1,
10850 .info = alc_mux_enum_info,
10851 .get = alc_mux_enum_get,
10852 .put = alc_mux_enum_put,
10853 },
10854 {
10855 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10856 .name = "Channel Mode",
10857 .info = alc_ch_mode_info,
10858 .get = alc_ch_mode_get,
10859 .put = alc_ch_mode_put,
10860 .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
10861 },
10862 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010863};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020010864
10865static struct snd_kcontrol_new alc861_asus_mixer[] = {
10866 /* output mixer control */
10867 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
10868 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
10869 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
10870 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
10871 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
10872
10873 /* Input mixer control */
10874 HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
10875 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10876 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
10877 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
10878 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
10879 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
10880 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
10881 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
10882 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010883 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
10884
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020010885 /* Capture mixer control */
10886 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
10887 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
10888 {
10889 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10890 .name = "Capture Source",
10891 .count = 1,
10892 .info = alc_mux_enum_info,
10893 .get = alc_mux_enum_get,
10894 .put = alc_mux_enum_put,
10895 },
10896 {
10897 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10898 .name = "Channel Mode",
10899 .info = alc_ch_mode_info,
10900 .get = alc_ch_mode_get,
10901 .put = alc_ch_mode_put,
10902 .private_value = ARRAY_SIZE(alc861_asus_modes),
10903 },
10904 { }
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010010905};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020010906
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010010907/* additional mixer */
Takashi Iwaid1d985f2006-11-23 19:27:12 +010010908static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010010909 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
10910 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
10911 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x23, 0x0, HDA_OUTPUT),
10912 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x23, 0x0, HDA_OUTPUT),
10913 { }
10914};
10915
Kailang Yangdf694da2005-12-05 19:42:22 +010010916/*
10917 * generic initialization of ADC, input mixers and output mixers
10918 */
10919static struct hda_verb alc861_base_init_verbs[] = {
10920 /*
10921 * Unmute ADC0 and set the default input to mic-in
10922 */
10923 /* port-A for surround (rear panel) */
10924 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10925 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
10926 /* port-B for mic-in (rear panel) with vref */
10927 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10928 /* port-C for line-in (rear panel) */
10929 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
10930 /* port-D for Front */
10931 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10932 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
10933 /* port-E for HP out (front panel) */
10934 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
10935 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010010936 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010010937 /* port-F for mic-in (front panel) with vref */
10938 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10939 /* port-G for CLFE (rear panel) */
10940 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10941 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
10942 /* port-H for side (rear panel) */
10943 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10944 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
10945 /* CD-in */
10946 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
10947 /* route front mic to ADC1*/
10948 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
10949 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10950
10951 /* Unmute DAC0~3 & spdif out*/
10952 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10953 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10954 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10955 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10956 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10957
10958 /* Unmute Mixer 14 (mic) 1c (Line in)*/
10959 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10960 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10961 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10962 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10963
10964 /* Unmute Stereo Mixer 15 */
10965 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10966 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10967 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010968 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010010969
10970 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10971 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10972 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10973 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10974 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10975 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10976 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10977 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010978 /* hp used DAC 3 (Front) */
10979 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010010980 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
10981
10982 { }
10983};
10984
10985static struct hda_verb alc861_threestack_init_verbs[] = {
10986 /*
10987 * Unmute ADC0 and set the default input to mic-in
10988 */
10989 /* port-A for surround (rear panel) */
10990 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
10991 /* port-B for mic-in (rear panel) with vref */
10992 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10993 /* port-C for line-in (rear panel) */
10994 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
10995 /* port-D for Front */
10996 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10997 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
10998 /* port-E for HP out (front panel) */
10999 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
11000 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010011001 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010011002 /* port-F for mic-in (front panel) with vref */
11003 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
11004 /* port-G for CLFE (rear panel) */
11005 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
11006 /* port-H for side (rear panel) */
11007 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
11008 /* CD-in */
11009 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
11010 /* route front mic to ADC1*/
11011 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11012 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11013 /* Unmute DAC0~3 & spdif out*/
11014 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11015 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11016 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11017 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11018 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11019
11020 /* Unmute Mixer 14 (mic) 1c (Line in)*/
11021 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11022 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11023 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11024 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11025
11026 /* Unmute Stereo Mixer 15 */
11027 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11028 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11029 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011030 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010011031
11032 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11033 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11034 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11035 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11036 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11037 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11038 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11039 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011040 /* hp used DAC 3 (Front) */
11041 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011042 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
11043 { }
11044};
Takashi Iwai22309c32006-08-09 16:57:28 +020011045
11046static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
11047 /*
11048 * Unmute ADC0 and set the default input to mic-in
11049 */
11050 /* port-A for surround (rear panel) */
11051 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
11052 /* port-B for mic-in (rear panel) with vref */
11053 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
11054 /* port-C for line-in (rear panel) */
11055 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
11056 /* port-D for Front */
11057 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11058 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
11059 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011060 /* this has to be set to VREF80 */
11061 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Takashi Iwai22309c32006-08-09 16:57:28 +020011062 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010011063 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai22309c32006-08-09 16:57:28 +020011064 /* port-F for mic-in (front panel) with vref */
11065 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
11066 /* port-G for CLFE (rear panel) */
11067 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
11068 /* port-H for side (rear panel) */
11069 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
11070 /* CD-in */
11071 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
11072 /* route front mic to ADC1*/
11073 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11074 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11075 /* Unmute DAC0~3 & spdif out*/
11076 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11077 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11078 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11079 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11080 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11081
11082 /* Unmute Mixer 14 (mic) 1c (Line in)*/
11083 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11084 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11085 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11086 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11087
11088 /* Unmute Stereo Mixer 15 */
11089 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11090 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11091 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011092 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Takashi Iwai22309c32006-08-09 16:57:28 +020011093
11094 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11095 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11096 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11097 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11098 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11099 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11100 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11101 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011102 /* hp used DAC 3 (Front) */
11103 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Takashi Iwai22309c32006-08-09 16:57:28 +020011104 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
11105 { }
11106};
11107
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011108static struct hda_verb alc861_asus_init_verbs[] = {
11109 /*
11110 * Unmute ADC0 and set the default input to mic-in
11111 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011112 /* port-A for surround (rear panel)
11113 * according to codec#0 this is the HP jack
11114 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011115 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
11116 /* route front PCM to HP */
11117 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
11118 /* port-B for mic-in (rear panel) with vref */
11119 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
11120 /* port-C for line-in (rear panel) */
11121 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
11122 /* port-D for Front */
11123 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11124 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
11125 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011126 /* this has to be set to VREF80 */
11127 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011128 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010011129 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011130 /* port-F for mic-in (front panel) with vref */
11131 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
11132 /* port-G for CLFE (rear panel) */
11133 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11134 /* port-H for side (rear panel) */
11135 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11136 /* CD-in */
11137 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
11138 /* route front mic to ADC1*/
11139 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11140 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11141 /* Unmute DAC0~3 & spdif out*/
11142 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11143 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11144 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11145 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11146 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11147 /* Unmute Mixer 14 (mic) 1c (Line in)*/
11148 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11149 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11150 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11151 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11152
11153 /* Unmute Stereo Mixer 15 */
11154 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11155 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11156 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011157 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011158
11159 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11160 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11161 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11162 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11163 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11164 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11165 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11166 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011167 /* hp used DAC 3 (Front) */
11168 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011169 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
11170 { }
11171};
11172
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010011173/* additional init verbs for ASUS laptops */
11174static struct hda_verb alc861_asus_laptop_init_verbs[] = {
11175 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
11176 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
11177 { }
11178};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011179
Kailang Yangdf694da2005-12-05 19:42:22 +010011180/*
11181 * generic initialization of ADC, input mixers and output mixers
11182 */
11183static struct hda_verb alc861_auto_init_verbs[] = {
11184 /*
11185 * Unmute ADC0 and set the default input to mic-in
11186 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011187 /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */
Kailang Yangdf694da2005-12-05 19:42:22 +010011188 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11189
11190 /* Unmute DAC0~3 & spdif out*/
11191 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11192 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11193 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11194 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11195 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11196
11197 /* Unmute Mixer 14 (mic) 1c (Line in)*/
11198 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11199 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11200 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11201 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11202
11203 /* Unmute Stereo Mixer 15 */
11204 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11205 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11206 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
11207 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
11208
11209 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11210 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11211 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11212 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11213 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11214 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11215 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11216 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11217
11218 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11219 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011220 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
11221 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011222 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11223 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011224 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
11225 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011226
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011227 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */
Kailang Yangdf694da2005-12-05 19:42:22 +010011228
11229 { }
11230};
11231
Tobin Davisa53d1ae2006-10-17 12:00:28 +020011232static struct hda_verb alc861_toshiba_init_verbs[] = {
11233 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011234
Tobin Davisa53d1ae2006-10-17 12:00:28 +020011235 { }
11236};
11237
11238/* toggle speaker-output according to the hp-jack state */
11239static void alc861_toshiba_automute(struct hda_codec *codec)
11240{
11241 unsigned int present;
11242
11243 present = snd_hda_codec_read(codec, 0x0f, 0,
11244 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020011245 snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
11246 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
11247 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
11248 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020011249}
11250
11251static void alc861_toshiba_unsol_event(struct hda_codec *codec,
11252 unsigned int res)
11253{
Tobin Davisa53d1ae2006-10-17 12:00:28 +020011254 if ((res >> 26) == ALC880_HP_EVENT)
11255 alc861_toshiba_automute(codec);
11256}
11257
Kailang Yangdf694da2005-12-05 19:42:22 +010011258/* pcm configuration: identiacal with ALC880 */
11259#define alc861_pcm_analog_playback alc880_pcm_analog_playback
11260#define alc861_pcm_analog_capture alc880_pcm_analog_capture
11261#define alc861_pcm_digital_playback alc880_pcm_digital_playback
11262#define alc861_pcm_digital_capture alc880_pcm_digital_capture
11263
11264
11265#define ALC861_DIGOUT_NID 0x07
11266
11267static struct hda_channel_mode alc861_8ch_modes[1] = {
11268 { 8, NULL }
11269};
11270
11271static hda_nid_t alc861_dac_nids[4] = {
11272 /* front, surround, clfe, side */
11273 0x03, 0x06, 0x05, 0x04
11274};
11275
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011276static hda_nid_t alc660_dac_nids[3] = {
11277 /* front, clfe, surround */
11278 0x03, 0x05, 0x06
11279};
11280
Kailang Yangdf694da2005-12-05 19:42:22 +010011281static hda_nid_t alc861_adc_nids[1] = {
11282 /* ADC0-2 */
11283 0x08,
11284};
11285
11286static struct hda_input_mux alc861_capture_source = {
11287 .num_items = 5,
11288 .items = {
11289 { "Mic", 0x0 },
11290 { "Front Mic", 0x3 },
11291 { "Line", 0x1 },
11292 { "CD", 0x4 },
11293 { "Mixer", 0x5 },
11294 },
11295};
11296
11297/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011298static int alc861_auto_fill_dac_nids(struct alc_spec *spec,
11299 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010011300{
11301 int i;
11302 hda_nid_t nid;
11303
11304 spec->multiout.dac_nids = spec->private_dac_nids;
11305 for (i = 0; i < cfg->line_outs; i++) {
11306 nid = cfg->line_out_pins[i];
11307 if (nid) {
11308 if (i >= ARRAY_SIZE(alc861_dac_nids))
11309 continue;
11310 spec->multiout.dac_nids[i] = alc861_dac_nids[i];
11311 }
11312 }
11313 spec->multiout.num_dacs = cfg->line_outs;
11314 return 0;
11315}
11316
11317/* add playback controls from the parsed DAC table */
11318static int alc861_auto_create_multi_out_ctls(struct alc_spec *spec,
11319 const struct auto_pin_cfg *cfg)
11320{
11321 char name[32];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011322 static const char *chname[4] = {
11323 "Front", "Surround", NULL /*CLFE*/, "Side"
11324 };
Kailang Yangdf694da2005-12-05 19:42:22 +010011325 hda_nid_t nid;
11326 int i, idx, err;
11327
11328 for (i = 0; i < cfg->line_outs; i++) {
11329 nid = spec->multiout.dac_nids[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011330 if (!nid)
Kailang Yangdf694da2005-12-05 19:42:22 +010011331 continue;
11332 if (nid == 0x05) {
11333 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011334 err = add_control(spec, ALC_CTL_BIND_MUTE,
11335 "Center Playback Switch",
11336 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
11337 HDA_OUTPUT));
11338 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011339 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011340 err = add_control(spec, ALC_CTL_BIND_MUTE,
11341 "LFE Playback Switch",
11342 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
11343 HDA_OUTPUT));
11344 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011345 return err;
11346 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011347 for (idx = 0; idx < ARRAY_SIZE(alc861_dac_nids) - 1;
11348 idx++)
Kailang Yangdf694da2005-12-05 19:42:22 +010011349 if (nid == alc861_dac_nids[idx])
11350 break;
11351 sprintf(name, "%s Playback Switch", chname[idx]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011352 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
11353 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
11354 HDA_OUTPUT));
11355 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011356 return err;
11357 }
11358 }
11359 return 0;
11360}
11361
11362static int alc861_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin)
11363{
11364 int err;
11365 hda_nid_t nid;
11366
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011367 if (!pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010011368 return 0;
11369
11370 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
11371 nid = 0x03;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011372 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
11373 "Headphone Playback Switch",
11374 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
11375 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011376 return err;
11377 spec->multiout.hp_nid = nid;
11378 }
11379 return 0;
11380}
11381
11382/* create playback/capture controls for input pins */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011383static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec,
11384 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010011385{
Kailang Yangdf694da2005-12-05 19:42:22 +010011386 struct hda_input_mux *imux = &spec->private_imux;
11387 int i, err, idx, idx1;
11388
11389 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011390 switch (cfg->input_pins[i]) {
Kailang Yangdf694da2005-12-05 19:42:22 +010011391 case 0x0c:
11392 idx1 = 1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011393 idx = 2; /* Line In */
Kailang Yangdf694da2005-12-05 19:42:22 +010011394 break;
11395 case 0x0f:
11396 idx1 = 2;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011397 idx = 2; /* Line In */
Kailang Yangdf694da2005-12-05 19:42:22 +010011398 break;
11399 case 0x0d:
11400 idx1 = 0;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011401 idx = 1; /* Mic In */
Kailang Yangdf694da2005-12-05 19:42:22 +010011402 break;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011403 case 0x10:
Kailang Yangdf694da2005-12-05 19:42:22 +010011404 idx1 = 3;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011405 idx = 1; /* Mic In */
Kailang Yangdf694da2005-12-05 19:42:22 +010011406 break;
11407 case 0x11:
11408 idx1 = 4;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011409 idx = 0; /* CD */
Kailang Yangdf694da2005-12-05 19:42:22 +010011410 break;
11411 default:
11412 continue;
11413 }
11414
Takashi Iwai4a471b72005-12-07 13:56:29 +010011415 err = new_analog_input(spec, cfg->input_pins[i],
11416 auto_pin_cfg_labels[i], idx, 0x15);
Kailang Yangdf694da2005-12-05 19:42:22 +010011417 if (err < 0)
11418 return err;
11419
Takashi Iwai4a471b72005-12-07 13:56:29 +010011420 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +010011421 imux->items[imux->num_items].index = idx1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011422 imux->num_items++;
Kailang Yangdf694da2005-12-05 19:42:22 +010011423 }
11424 return 0;
11425}
11426
11427static struct snd_kcontrol_new alc861_capture_mixer[] = {
11428 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
11429 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
11430
11431 {
11432 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11433 /* The multiple "Capture Source" controls confuse alsamixer
11434 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +010011435 */
11436 /* .name = "Capture Source", */
11437 .name = "Input Source",
11438 .count = 1,
11439 .info = alc_mux_enum_info,
11440 .get = alc_mux_enum_get,
11441 .put = alc_mux_enum_put,
11442 },
11443 { } /* end */
11444};
11445
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011446static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
11447 hda_nid_t nid,
Kailang Yangdf694da2005-12-05 19:42:22 +010011448 int pin_type, int dac_idx)
11449{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011450 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010011451}
11452
11453static void alc861_auto_init_multi_out(struct hda_codec *codec)
11454{
11455 struct alc_spec *spec = codec->spec;
11456 int i;
11457
Kailang Yangbc9f98a2007-04-12 13:06:07 +020011458 alc_subsystem_id(codec, 0x0e, 0x0f, 0x0b);
Kailang Yangdf694da2005-12-05 19:42:22 +010011459 for (i = 0; i < spec->autocfg.line_outs; i++) {
11460 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020011461 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010011462 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020011463 alc861_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011464 spec->multiout.dac_nids[i]);
Kailang Yangdf694da2005-12-05 19:42:22 +010011465 }
11466}
11467
11468static void alc861_auto_init_hp_out(struct hda_codec *codec)
11469{
11470 struct alc_spec *spec = codec->spec;
11471 hda_nid_t pin;
11472
Takashi Iwaieb06ed82006-09-20 17:10:27 +020011473 pin = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010011474 if (pin) /* connect to front */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011475 alc861_auto_set_output_and_unmute(codec, pin, PIN_HP,
11476 spec->multiout.dac_nids[0]);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011477 pin = spec->autocfg.speaker_pins[0];
11478 if (pin)
11479 alc861_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +010011480}
11481
11482static void alc861_auto_init_analog_input(struct hda_codec *codec)
11483{
11484 struct alc_spec *spec = codec->spec;
11485 int i;
11486
11487 for (i = 0; i < AUTO_PIN_LAST; i++) {
11488 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011489 if (nid >= 0x0c && nid <= 0x11) {
11490 snd_hda_codec_write(codec, nid, 0,
11491 AC_VERB_SET_PIN_WIDGET_CONTROL,
11492 i <= AUTO_PIN_FRONT_MIC ?
11493 PIN_VREF80 : PIN_IN);
Kailang Yangdf694da2005-12-05 19:42:22 +010011494 }
11495 }
11496}
11497
11498/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011499/* return 1 if successful, 0 if the proper config is not found,
11500 * or a negative error code
11501 */
Kailang Yangdf694da2005-12-05 19:42:22 +010011502static int alc861_parse_auto_config(struct hda_codec *codec)
11503{
11504 struct alc_spec *spec = codec->spec;
11505 int err;
11506 static hda_nid_t alc861_ignore[] = { 0x1d, 0 };
11507
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011508 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
11509 alc861_ignore);
11510 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011511 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011512 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010011513 return 0; /* can't find valid BIOS pin config */
11514
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011515 err = alc861_auto_fill_dac_nids(spec, &spec->autocfg);
11516 if (err < 0)
11517 return err;
11518 err = alc861_auto_create_multi_out_ctls(spec, &spec->autocfg);
11519 if (err < 0)
11520 return err;
11521 err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
11522 if (err < 0)
11523 return err;
11524 err = alc861_auto_create_analog_input_ctls(spec, &spec->autocfg);
11525 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011526 return err;
11527
11528 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
11529
11530 if (spec->autocfg.dig_out_pin)
11531 spec->multiout.dig_out_nid = ALC861_DIGOUT_NID;
11532
11533 if (spec->kctl_alloc)
11534 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
11535
11536 spec->init_verbs[spec->num_init_verbs++] = alc861_auto_init_verbs;
11537
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020011538 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +010011539 spec->input_mux = &spec->private_imux;
11540
11541 spec->adc_nids = alc861_adc_nids;
11542 spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
11543 spec->mixers[spec->num_mixers] = alc861_capture_mixer;
11544 spec->num_mixers++;
11545
11546 return 1;
11547}
11548
Takashi Iwaiae6b8132006-03-03 16:47:17 +010011549/* additional initialization for auto-configuration model */
11550static void alc861_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010011551{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011552 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010011553 alc861_auto_init_multi_out(codec);
11554 alc861_auto_init_hp_out(codec);
11555 alc861_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011556 if (spec->unsol_event)
11557 alc_sku_automute(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010011558}
11559
Takashi Iwaicb53c622007-08-10 17:21:45 +020011560#ifdef CONFIG_SND_HDA_POWER_SAVE
11561static struct hda_amp_list alc861_loopbacks[] = {
11562 { 0x15, HDA_INPUT, 0 },
11563 { 0x15, HDA_INPUT, 1 },
11564 { 0x15, HDA_INPUT, 2 },
11565 { 0x15, HDA_INPUT, 3 },
11566 { } /* end */
11567};
11568#endif
11569
Kailang Yangdf694da2005-12-05 19:42:22 +010011570
11571/*
11572 * configuration and preset
11573 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011574static const char *alc861_models[ALC861_MODEL_LAST] = {
11575 [ALC861_3ST] = "3stack",
11576 [ALC660_3ST] = "3stack-660",
11577 [ALC861_3ST_DIG] = "3stack-dig",
11578 [ALC861_6ST_DIG] = "6stack-dig",
11579 [ALC861_UNIWILL_M31] = "uniwill-m31",
11580 [ALC861_TOSHIBA] = "toshiba",
11581 [ALC861_ASUS] = "asus",
11582 [ALC861_ASUS_LAPTOP] = "asus-laptop",
11583 [ALC861_AUTO] = "auto",
11584};
11585
11586static struct snd_pci_quirk alc861_cfg_tbl[] = {
Takashi Iwai687a47b2007-01-10 11:25:58 +010011587 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011588 SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
11589 SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
11590 SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011591 SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
Kailang Yang83c34212007-07-05 11:43:05 +020011592 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
Tobin Davisad5e7732007-01-08 10:57:32 +010011593 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
Takashi Iwai341d4eb2007-07-09 17:53:18 +020011594 /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
11595 * Any other models that need this preset?
11596 */
11597 /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
Claudio Matsuokaef64adb2007-07-14 00:26:16 +020011598 SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
11599 SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011600 SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
11601 SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
11602 SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
11603 /* FIXME: the below seems conflict */
11604 /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
11605 SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
11606 SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
Kailang Yangdf694da2005-12-05 19:42:22 +010011607 {}
11608};
11609
11610static struct alc_config_preset alc861_presets[] = {
11611 [ALC861_3ST] = {
11612 .mixers = { alc861_3ST_mixer },
11613 .init_verbs = { alc861_threestack_init_verbs },
11614 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
11615 .dac_nids = alc861_dac_nids,
11616 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
11617 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020011618 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010011619 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11620 .adc_nids = alc861_adc_nids,
11621 .input_mux = &alc861_capture_source,
11622 },
11623 [ALC861_3ST_DIG] = {
11624 .mixers = { alc861_base_mixer },
11625 .init_verbs = { alc861_threestack_init_verbs },
11626 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
11627 .dac_nids = alc861_dac_nids,
11628 .dig_out_nid = ALC861_DIGOUT_NID,
11629 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
11630 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020011631 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010011632 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11633 .adc_nids = alc861_adc_nids,
11634 .input_mux = &alc861_capture_source,
11635 },
11636 [ALC861_6ST_DIG] = {
11637 .mixers = { alc861_base_mixer },
11638 .init_verbs = { alc861_base_init_verbs },
11639 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
11640 .dac_nids = alc861_dac_nids,
11641 .dig_out_nid = ALC861_DIGOUT_NID,
11642 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
11643 .channel_mode = alc861_8ch_modes,
11644 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11645 .adc_nids = alc861_adc_nids,
11646 .input_mux = &alc861_capture_source,
11647 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011648 [ALC660_3ST] = {
11649 .mixers = { alc861_3ST_mixer },
11650 .init_verbs = { alc861_threestack_init_verbs },
11651 .num_dacs = ARRAY_SIZE(alc660_dac_nids),
11652 .dac_nids = alc660_dac_nids,
11653 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
11654 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020011655 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011656 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11657 .adc_nids = alc861_adc_nids,
11658 .input_mux = &alc861_capture_source,
11659 },
Takashi Iwai22309c32006-08-09 16:57:28 +020011660 [ALC861_UNIWILL_M31] = {
11661 .mixers = { alc861_uniwill_m31_mixer },
11662 .init_verbs = { alc861_uniwill_m31_init_verbs },
11663 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
11664 .dac_nids = alc861_dac_nids,
11665 .dig_out_nid = ALC861_DIGOUT_NID,
11666 .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
11667 .channel_mode = alc861_uniwill_m31_modes,
11668 .need_dac_fix = 1,
11669 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11670 .adc_nids = alc861_adc_nids,
11671 .input_mux = &alc861_capture_source,
11672 },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020011673 [ALC861_TOSHIBA] = {
11674 .mixers = { alc861_toshiba_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011675 .init_verbs = { alc861_base_init_verbs,
11676 alc861_toshiba_init_verbs },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020011677 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
11678 .dac_nids = alc861_dac_nids,
11679 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
11680 .channel_mode = alc883_3ST_2ch_modes,
11681 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11682 .adc_nids = alc861_adc_nids,
11683 .input_mux = &alc861_capture_source,
11684 .unsol_event = alc861_toshiba_unsol_event,
11685 .init_hook = alc861_toshiba_automute,
11686 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011687 [ALC861_ASUS] = {
11688 .mixers = { alc861_asus_mixer },
11689 .init_verbs = { alc861_asus_init_verbs },
11690 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
11691 .dac_nids = alc861_dac_nids,
11692 .dig_out_nid = ALC861_DIGOUT_NID,
11693 .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
11694 .channel_mode = alc861_asus_modes,
11695 .need_dac_fix = 1,
11696 .hp_nid = 0x06,
11697 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11698 .adc_nids = alc861_adc_nids,
11699 .input_mux = &alc861_capture_source,
11700 },
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010011701 [ALC861_ASUS_LAPTOP] = {
11702 .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
11703 .init_verbs = { alc861_asus_init_verbs,
11704 alc861_asus_laptop_init_verbs },
11705 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
11706 .dac_nids = alc861_dac_nids,
11707 .dig_out_nid = ALC861_DIGOUT_NID,
11708 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
11709 .channel_mode = alc883_3ST_2ch_modes,
11710 .need_dac_fix = 1,
11711 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11712 .adc_nids = alc861_adc_nids,
11713 .input_mux = &alc861_capture_source,
11714 },
11715};
Kailang Yangdf694da2005-12-05 19:42:22 +010011716
11717
11718static int patch_alc861(struct hda_codec *codec)
11719{
11720 struct alc_spec *spec;
11721 int board_config;
11722 int err;
11723
Robert P. J. Daydc041e02006-12-19 14:44:15 +010011724 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010011725 if (spec == NULL)
11726 return -ENOMEM;
11727
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011728 codec->spec = spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010011729
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011730 board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
11731 alc861_models,
11732 alc861_cfg_tbl);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011733
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011734 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011735 printk(KERN_INFO "hda_codec: Unknown model for ALC861, "
11736 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010011737 board_config = ALC861_AUTO;
11738 }
11739
11740 if (board_config == ALC861_AUTO) {
11741 /* automatic parse from the BIOS config */
11742 err = alc861_parse_auto_config(codec);
11743 if (err < 0) {
11744 alc_free(codec);
11745 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011746 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011747 printk(KERN_INFO
11748 "hda_codec: Cannot set up configuration "
11749 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010011750 board_config = ALC861_3ST_DIG;
11751 }
11752 }
11753
11754 if (board_config != ALC861_AUTO)
11755 setup_preset(spec, &alc861_presets[board_config]);
11756
11757 spec->stream_name_analog = "ALC861 Analog";
11758 spec->stream_analog_playback = &alc861_pcm_analog_playback;
11759 spec->stream_analog_capture = &alc861_pcm_analog_capture;
11760
11761 spec->stream_name_digital = "ALC861 Digital";
11762 spec->stream_digital_playback = &alc861_pcm_digital_playback;
11763 spec->stream_digital_capture = &alc861_pcm_digital_capture;
11764
Takashi Iwai2134ea42008-01-10 16:53:55 +010011765 spec->vmaster_nid = 0x03;
11766
Kailang Yangdf694da2005-12-05 19:42:22 +010011767 codec->patch_ops = alc_patch_ops;
11768 if (board_config == ALC861_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010011769 spec->init_hook = alc861_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020011770#ifdef CONFIG_SND_HDA_POWER_SAVE
11771 if (!spec->loopback.amplist)
11772 spec->loopback.amplist = alc861_loopbacks;
11773#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010011774
11775 return 0;
11776}
11777
11778/*
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011779 * ALC861-VD support
11780 *
11781 * Based on ALC882
11782 *
11783 * In addition, an independent DAC
11784 */
11785#define ALC861VD_DIGOUT_NID 0x06
11786
11787static hda_nid_t alc861vd_dac_nids[4] = {
11788 /* front, surr, clfe, side surr */
11789 0x02, 0x03, 0x04, 0x05
11790};
11791
11792/* dac_nids for ALC660vd are in a different order - according to
11793 * Realtek's driver.
11794 * This should probably tesult in a different mixer for 6stack models
11795 * of ALC660vd codecs, but for now there is only 3stack mixer
11796 * - and it is the same as in 861vd.
11797 * adc_nids in ALC660vd are (is) the same as in 861vd
11798 */
11799static hda_nid_t alc660vd_dac_nids[3] = {
11800 /* front, rear, clfe, rear_surr */
11801 0x02, 0x04, 0x03
11802};
11803
11804static hda_nid_t alc861vd_adc_nids[1] = {
11805 /* ADC0 */
11806 0x09,
11807};
11808
Takashi Iwaie1406342008-02-11 18:32:32 +010011809static hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
11810
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011811/* input MUX */
11812/* FIXME: should be a matrix-type input source selection */
11813static struct hda_input_mux alc861vd_capture_source = {
11814 .num_items = 4,
11815 .items = {
11816 { "Mic", 0x0 },
11817 { "Front Mic", 0x1 },
11818 { "Line", 0x2 },
11819 { "CD", 0x4 },
11820 },
11821};
11822
Kailang Yang272a5272007-05-14 11:00:38 +020011823static struct hda_input_mux alc861vd_dallas_capture_source = {
11824 .num_items = 3,
11825 .items = {
11826 { "Front Mic", 0x0 },
11827 { "ATAPI Mic", 0x1 },
11828 { "Line In", 0x5 },
11829 },
11830};
11831
Kailang Yangd1a991a2007-08-15 16:21:59 +020011832static struct hda_input_mux alc861vd_hp_capture_source = {
11833 .num_items = 2,
11834 .items = {
11835 { "Front Mic", 0x0 },
11836 { "ATAPI Mic", 0x1 },
11837 },
11838};
11839
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011840#define alc861vd_mux_enum_info alc_mux_enum_info
11841#define alc861vd_mux_enum_get alc_mux_enum_get
Takashi Iwaie1406342008-02-11 18:32:32 +010011842/* ALC861VD has the ALC882-type input selection (but has only one ADC) */
11843#define alc861vd_mux_enum_put alc882_mux_enum_put
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011844
11845/*
11846 * 2ch mode
11847 */
11848static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
11849 { 2, NULL }
11850};
11851
11852/*
11853 * 6ch mode
11854 */
11855static struct hda_verb alc861vd_6stack_ch6_init[] = {
11856 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
11857 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11858 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11859 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11860 { } /* end */
11861};
11862
11863/*
11864 * 8ch mode
11865 */
11866static struct hda_verb alc861vd_6stack_ch8_init[] = {
11867 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11868 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11869 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11870 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11871 { } /* end */
11872};
11873
11874static struct hda_channel_mode alc861vd_6stack_modes[2] = {
11875 { 6, alc861vd_6stack_ch6_init },
11876 { 8, alc861vd_6stack_ch8_init },
11877};
11878
11879static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
11880 {
11881 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11882 .name = "Channel Mode",
11883 .info = alc_ch_mode_info,
11884 .get = alc_ch_mode_get,
11885 .put = alc_ch_mode_put,
11886 },
11887 { } /* end */
11888};
11889
11890static struct snd_kcontrol_new alc861vd_capture_mixer[] = {
11891 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
11892 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
11893
11894 {
11895 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11896 /* The multiple "Capture Source" controls confuse alsamixer
11897 * So call somewhat different..
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011898 */
11899 /* .name = "Capture Source", */
11900 .name = "Input Source",
11901 .count = 1,
11902 .info = alc861vd_mux_enum_info,
11903 .get = alc861vd_mux_enum_get,
11904 .put = alc861vd_mux_enum_put,
11905 },
11906 { } /* end */
11907};
11908
11909/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
11910 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
11911 */
11912static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
11913 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11914 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
11915
11916 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
11917 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
11918
11919 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
11920 HDA_OUTPUT),
11921 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
11922 HDA_OUTPUT),
11923 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
11924 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
11925
11926 HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
11927 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
11928
11929 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
11930
11931 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11932 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11933 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11934
11935 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11936 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11937 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
11938
11939 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11940 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11941
11942 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11943 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11944
11945 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
11946 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
11947
11948 { } /* end */
11949};
11950
11951static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
11952 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11953 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
11954
11955 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
11956
11957 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11958 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11959 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11960
11961 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11962 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11963 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
11964
11965 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11966 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11967
11968 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11969 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11970
11971 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
11972 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
11973
11974 { } /* end */
11975};
11976
Kailang Yangbdd148a2007-05-08 15:19:08 +020011977static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
11978 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11979 /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
11980 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11981
11982 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
11983
11984 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11985 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11986 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11987
11988 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11989 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11990 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
11991
11992 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11993 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11994
11995 { } /* end */
11996};
11997
Kailang Yang272a5272007-05-14 11:00:38 +020011998/* Pin assignment: Front=0x14, HP = 0x15,
11999 * Front Mic=0x18, ATAPI Mic = 0x19, Line In = 0x1d
12000 */
12001static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
12002 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12003 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
12004 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
12005 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
12006 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12007 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12008 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12009 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
12010 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x05, HDA_INPUT),
12011 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020012012 { } /* end */
12013};
12014
Kailang Yangd1a991a2007-08-15 16:21:59 +020012015/* Pin assignment: Speaker=0x14, Line-out = 0x15,
12016 * Front Mic=0x18, ATAPI Mic = 0x19,
12017 */
12018static struct snd_kcontrol_new alc861vd_hp_mixer[] = {
12019 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12020 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
12021 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
12022 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
12023 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12024 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12025 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12026 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
12027
12028 { } /* end */
12029};
12030
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012031/*
12032 * generic initialization of ADC, input mixers and output mixers
12033 */
12034static struct hda_verb alc861vd_volume_init_verbs[] = {
12035 /*
12036 * Unmute ADC0 and set the default input to mic-in
12037 */
12038 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12039 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12040
12041 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
12042 * the analog-loopback mixer widget
12043 */
12044 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020012045 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12046 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12047 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12048 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12049 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012050
12051 /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yangbdd148a2007-05-08 15:19:08 +020012052 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12053 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12054 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012055 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012056
12057 /*
12058 * Set up output mixers (0x02 - 0x05)
12059 */
12060 /* set vol=0 to output mixers */
12061 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12062 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12063 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12064 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12065
12066 /* set up input amps for analog loopback */
12067 /* Amp Indices: DAC = 0, mixer = 1 */
12068 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12069 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12070 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12071 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12072 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12073 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12074 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12075 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12076
12077 { }
12078};
12079
12080/*
12081 * 3-stack pin configuration:
12082 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
12083 */
12084static struct hda_verb alc861vd_3stack_init_verbs[] = {
12085 /*
12086 * Set pin mode and muting
12087 */
12088 /* set front pin widgets 0x14 for output */
12089 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12090 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12091 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
12092
12093 /* Mic (rear) pin: input vref at 80% */
12094 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12095 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12096 /* Front Mic pin: input vref at 80% */
12097 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12098 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12099 /* Line In pin: input */
12100 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12101 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12102 /* Line-2 In: Headphone output (output 0 - 0x0c) */
12103 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12104 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12105 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
12106 /* CD pin widget for input */
12107 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12108
12109 { }
12110};
12111
12112/*
12113 * 6-stack pin configuration:
12114 */
12115static struct hda_verb alc861vd_6stack_init_verbs[] = {
12116 /*
12117 * Set pin mode and muting
12118 */
12119 /* set front pin widgets 0x14 for output */
12120 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12121 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12122 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
12123
12124 /* Rear Pin: output 1 (0x0d) */
12125 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12126 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12127 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12128 /* CLFE Pin: output 2 (0x0e) */
12129 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12130 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12131 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
12132 /* Side Pin: output 3 (0x0f) */
12133 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12134 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12135 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
12136
12137 /* Mic (rear) pin: input vref at 80% */
12138 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12139 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12140 /* Front Mic pin: input vref at 80% */
12141 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12142 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12143 /* Line In pin: input */
12144 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12145 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12146 /* Line-2 In: Headphone output (output 0 - 0x0c) */
12147 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12148 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12149 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
12150 /* CD pin widget for input */
12151 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12152
12153 { }
12154};
12155
Kailang Yangbdd148a2007-05-08 15:19:08 +020012156static struct hda_verb alc861vd_eapd_verbs[] = {
12157 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
12158 { }
12159};
12160
12161static struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
12162 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12163 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12164 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
12165 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12166 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
12167 {}
12168};
12169
12170/* toggle speaker-output according to the hp-jack state */
12171static void alc861vd_lenovo_hp_automute(struct hda_codec *codec)
12172{
12173 unsigned int present;
12174 unsigned char bits;
12175
12176 present = snd_hda_codec_read(codec, 0x1b, 0,
12177 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020012178 bits = present ? HDA_AMP_MUTE : 0;
12179 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
12180 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020012181}
12182
12183static void alc861vd_lenovo_mic_automute(struct hda_codec *codec)
12184{
12185 unsigned int present;
12186 unsigned char bits;
12187
12188 present = snd_hda_codec_read(codec, 0x18, 0,
12189 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020012190 bits = present ? HDA_AMP_MUTE : 0;
12191 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
12192 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020012193}
12194
12195static void alc861vd_lenovo_automute(struct hda_codec *codec)
12196{
12197 alc861vd_lenovo_hp_automute(codec);
12198 alc861vd_lenovo_mic_automute(codec);
12199}
12200
12201static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
12202 unsigned int res)
12203{
12204 switch (res >> 26) {
12205 case ALC880_HP_EVENT:
12206 alc861vd_lenovo_hp_automute(codec);
12207 break;
12208 case ALC880_MIC_EVENT:
12209 alc861vd_lenovo_mic_automute(codec);
12210 break;
12211 }
12212}
12213
Kailang Yang272a5272007-05-14 11:00:38 +020012214static struct hda_verb alc861vd_dallas_verbs[] = {
12215 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12216 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12217 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12218 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12219
12220 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12221 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12222 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12223 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12224 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12225 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12226 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12227 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12228
12229 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12230 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12231 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12232 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12233 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12234 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12235 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12236 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12237
12238 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
12239 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12240 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
12241 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12242 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12243 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12244 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12245 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12246
12247 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12248 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12249 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12250 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12251
12252 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12253 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12254 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12255
12256 { } /* end */
12257};
12258
12259/* toggle speaker-output according to the hp-jack state */
12260static void alc861vd_dallas_automute(struct hda_codec *codec)
12261{
12262 unsigned int present;
12263
12264 present = snd_hda_codec_read(codec, 0x15, 0,
12265 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020012266 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
12267 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +020012268}
12269
12270static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int res)
12271{
12272 if ((res >> 26) == ALC880_HP_EVENT)
12273 alc861vd_dallas_automute(codec);
12274}
12275
Takashi Iwaicb53c622007-08-10 17:21:45 +020012276#ifdef CONFIG_SND_HDA_POWER_SAVE
12277#define alc861vd_loopbacks alc880_loopbacks
12278#endif
12279
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012280/* pcm configuration: identiacal with ALC880 */
12281#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback
12282#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture
12283#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback
12284#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture
12285
12286/*
12287 * configuration and preset
12288 */
12289static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
12290 [ALC660VD_3ST] = "3stack-660",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020012291 [ALC660VD_3ST_DIG] = "3stack-660-digout",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012292 [ALC861VD_3ST] = "3stack",
12293 [ALC861VD_3ST_DIG] = "3stack-digout",
12294 [ALC861VD_6ST_DIG] = "6stack-digout",
Kailang Yangbdd148a2007-05-08 15:19:08 +020012295 [ALC861VD_LENOVO] = "lenovo",
Kailang Yang272a5272007-05-14 11:00:38 +020012296 [ALC861VD_DALLAS] = "dallas",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020012297 [ALC861VD_HP] = "hp",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012298 [ALC861VD_AUTO] = "auto",
12299};
12300
12301static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012302 SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
12303 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
Takashi Iwai07e038b2007-02-15 18:23:41 +010012304 SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012305 SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),
Mike Crash6963f842007-06-25 12:12:51 +020012306 SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012307 SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012308 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai38baf5a2007-08-16 17:52:43 +020012309 /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
Kailang Yang272a5272007-05-14 11:00:38 +020012310 SND_PCI_QUIRK(0x1179, 0xff01, "DALLAS", ALC861VD_DALLAS),
Takashi Iwai542d7c62007-08-16 18:57:30 +020012311 SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
Takashi Iwai39c5d412007-08-15 16:24:17 +020012312 SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012313 SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO),
12314 SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO),
Tobin Davis625dc0b2007-07-30 21:42:10 +020012315 SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012316 {}
12317};
12318
12319static struct alc_config_preset alc861vd_presets[] = {
12320 [ALC660VD_3ST] = {
12321 .mixers = { alc861vd_3st_mixer },
12322 .init_verbs = { alc861vd_volume_init_verbs,
12323 alc861vd_3stack_init_verbs },
12324 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
12325 .dac_nids = alc660vd_dac_nids,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012326 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12327 .channel_mode = alc861vd_3stack_2ch_modes,
12328 .input_mux = &alc861vd_capture_source,
12329 },
Mike Crash6963f842007-06-25 12:12:51 +020012330 [ALC660VD_3ST_DIG] = {
12331 .mixers = { alc861vd_3st_mixer },
12332 .init_verbs = { alc861vd_volume_init_verbs,
12333 alc861vd_3stack_init_verbs },
12334 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
12335 .dac_nids = alc660vd_dac_nids,
12336 .dig_out_nid = ALC861VD_DIGOUT_NID,
Mike Crash6963f842007-06-25 12:12:51 +020012337 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12338 .channel_mode = alc861vd_3stack_2ch_modes,
12339 .input_mux = &alc861vd_capture_source,
12340 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012341 [ALC861VD_3ST] = {
12342 .mixers = { alc861vd_3st_mixer },
12343 .init_verbs = { alc861vd_volume_init_verbs,
12344 alc861vd_3stack_init_verbs },
12345 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
12346 .dac_nids = alc861vd_dac_nids,
12347 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12348 .channel_mode = alc861vd_3stack_2ch_modes,
12349 .input_mux = &alc861vd_capture_source,
12350 },
12351 [ALC861VD_3ST_DIG] = {
12352 .mixers = { alc861vd_3st_mixer },
12353 .init_verbs = { alc861vd_volume_init_verbs,
12354 alc861vd_3stack_init_verbs },
12355 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
12356 .dac_nids = alc861vd_dac_nids,
12357 .dig_out_nid = ALC861VD_DIGOUT_NID,
12358 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12359 .channel_mode = alc861vd_3stack_2ch_modes,
12360 .input_mux = &alc861vd_capture_source,
12361 },
12362 [ALC861VD_6ST_DIG] = {
12363 .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
12364 .init_verbs = { alc861vd_volume_init_verbs,
12365 alc861vd_6stack_init_verbs },
12366 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
12367 .dac_nids = alc861vd_dac_nids,
12368 .dig_out_nid = ALC861VD_DIGOUT_NID,
12369 .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
12370 .channel_mode = alc861vd_6stack_modes,
12371 .input_mux = &alc861vd_capture_source,
12372 },
Kailang Yangbdd148a2007-05-08 15:19:08 +020012373 [ALC861VD_LENOVO] = {
12374 .mixers = { alc861vd_lenovo_mixer },
12375 .init_verbs = { alc861vd_volume_init_verbs,
12376 alc861vd_3stack_init_verbs,
12377 alc861vd_eapd_verbs,
12378 alc861vd_lenovo_unsol_verbs },
12379 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
12380 .dac_nids = alc660vd_dac_nids,
Kailang Yangbdd148a2007-05-08 15:19:08 +020012381 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12382 .channel_mode = alc861vd_3stack_2ch_modes,
12383 .input_mux = &alc861vd_capture_source,
12384 .unsol_event = alc861vd_lenovo_unsol_event,
12385 .init_hook = alc861vd_lenovo_automute,
12386 },
Kailang Yang272a5272007-05-14 11:00:38 +020012387 [ALC861VD_DALLAS] = {
12388 .mixers = { alc861vd_dallas_mixer },
12389 .init_verbs = { alc861vd_dallas_verbs },
12390 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
12391 .dac_nids = alc861vd_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020012392 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12393 .channel_mode = alc861vd_3stack_2ch_modes,
12394 .input_mux = &alc861vd_dallas_capture_source,
12395 .unsol_event = alc861vd_dallas_unsol_event,
12396 .init_hook = alc861vd_dallas_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +020012397 },
12398 [ALC861VD_HP] = {
12399 .mixers = { alc861vd_hp_mixer },
12400 .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
12401 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
12402 .dac_nids = alc861vd_dac_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020012403 .dig_out_nid = ALC861VD_DIGOUT_NID,
Kailang Yangd1a991a2007-08-15 16:21:59 +020012404 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12405 .channel_mode = alc861vd_3stack_2ch_modes,
12406 .input_mux = &alc861vd_hp_capture_source,
12407 .unsol_event = alc861vd_dallas_unsol_event,
12408 .init_hook = alc861vd_dallas_automute,
12409 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012410};
12411
12412/*
12413 * BIOS auto configuration
12414 */
12415static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
12416 hda_nid_t nid, int pin_type, int dac_idx)
12417{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012418 alc_set_pin_output(codec, nid, pin_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012419}
12420
12421static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
12422{
12423 struct alc_spec *spec = codec->spec;
12424 int i;
12425
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012426 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012427 for (i = 0; i <= HDA_SIDE; i++) {
12428 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020012429 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012430 if (nid)
12431 alc861vd_auto_set_output_and_unmute(codec, nid,
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020012432 pin_type, i);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012433 }
12434}
12435
12436
12437static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
12438{
12439 struct alc_spec *spec = codec->spec;
12440 hda_nid_t pin;
12441
12442 pin = spec->autocfg.hp_pins[0];
12443 if (pin) /* connect to front and use dac 0 */
12444 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012445 pin = spec->autocfg.speaker_pins[0];
12446 if (pin)
12447 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012448}
12449
12450#define alc861vd_is_input_pin(nid) alc880_is_input_pin(nid)
12451#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID
12452
12453static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
12454{
12455 struct alc_spec *spec = codec->spec;
12456 int i;
12457
12458 for (i = 0; i < AUTO_PIN_LAST; i++) {
12459 hda_nid_t nid = spec->autocfg.input_pins[i];
12460 if (alc861vd_is_input_pin(nid)) {
12461 snd_hda_codec_write(codec, nid, 0,
12462 AC_VERB_SET_PIN_WIDGET_CONTROL,
12463 i <= AUTO_PIN_FRONT_MIC ?
12464 PIN_VREF80 : PIN_IN);
12465 if (nid != ALC861VD_PIN_CD_NID)
12466 snd_hda_codec_write(codec, nid, 0,
12467 AC_VERB_SET_AMP_GAIN_MUTE,
12468 AMP_OUT_MUTE);
12469 }
12470 }
12471}
12472
12473#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
12474#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
12475
12476/* add playback controls from the parsed DAC table */
12477/* Based on ALC880 version. But ALC861VD has separate,
12478 * different NIDs for mute/unmute switch and volume control */
12479static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
12480 const struct auto_pin_cfg *cfg)
12481{
12482 char name[32];
12483 static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
12484 hda_nid_t nid_v, nid_s;
12485 int i, err;
12486
12487 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012488 if (!spec->multiout.dac_nids[i])
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012489 continue;
12490 nid_v = alc861vd_idx_to_mixer_vol(
12491 alc880_dac_to_idx(
12492 spec->multiout.dac_nids[i]));
12493 nid_s = alc861vd_idx_to_mixer_switch(
12494 alc880_dac_to_idx(
12495 spec->multiout.dac_nids[i]));
12496
12497 if (i == 2) {
12498 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012499 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12500 "Center Playback Volume",
12501 HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
12502 HDA_OUTPUT));
12503 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012504 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012505 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12506 "LFE Playback Volume",
12507 HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
12508 HDA_OUTPUT));
12509 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012510 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012511 err = add_control(spec, ALC_CTL_BIND_MUTE,
12512 "Center Playback Switch",
12513 HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
12514 HDA_INPUT));
12515 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012516 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012517 err = add_control(spec, ALC_CTL_BIND_MUTE,
12518 "LFE Playback Switch",
12519 HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
12520 HDA_INPUT));
12521 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012522 return err;
12523 } else {
12524 sprintf(name, "%s Playback Volume", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012525 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
12526 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
12527 HDA_OUTPUT));
12528 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012529 return err;
12530 sprintf(name, "%s Playback Switch", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012531 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
Kailang Yangbdd148a2007-05-08 15:19:08 +020012532 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012533 HDA_INPUT));
12534 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012535 return err;
12536 }
12537 }
12538 return 0;
12539}
12540
12541/* add playback controls for speaker and HP outputs */
12542/* Based on ALC880 version. But ALC861VD has separate,
12543 * different NIDs for mute/unmute switch and volume control */
12544static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
12545 hda_nid_t pin, const char *pfx)
12546{
12547 hda_nid_t nid_v, nid_s;
12548 int err;
12549 char name[32];
12550
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012551 if (!pin)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012552 return 0;
12553
12554 if (alc880_is_fixed_pin(pin)) {
12555 nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
12556 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012557 if (!spec->multiout.hp_nid)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012558 spec->multiout.hp_nid = nid_v;
12559 else
12560 spec->multiout.extra_out_nid[0] = nid_v;
12561 /* control HP volume/switch on the output mixer amp */
12562 nid_v = alc861vd_idx_to_mixer_vol(
12563 alc880_fixed_pin_idx(pin));
12564 nid_s = alc861vd_idx_to_mixer_switch(
12565 alc880_fixed_pin_idx(pin));
12566
12567 sprintf(name, "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012568 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
12569 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
12570 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012571 return err;
12572 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012573 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
12574 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
12575 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012576 return err;
12577 } else if (alc880_is_multi_pin(pin)) {
12578 /* set manual connection */
12579 /* we have only a switch on HP-out PIN */
12580 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012581 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
12582 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
12583 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012584 return err;
12585 }
12586 return 0;
12587}
12588
12589/* parse the BIOS configuration and set up the alc_spec
12590 * return 1 if successful, 0 if the proper config is not found,
12591 * or a negative error code
12592 * Based on ALC880 version - had to change it to override
12593 * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
12594static int alc861vd_parse_auto_config(struct hda_codec *codec)
12595{
12596 struct alc_spec *spec = codec->spec;
12597 int err;
12598 static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
12599
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012600 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
12601 alc861vd_ignore);
12602 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012603 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012604 if (!spec->autocfg.line_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012605 return 0; /* can't find valid BIOS pin config */
12606
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012607 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
12608 if (err < 0)
12609 return err;
12610 err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
12611 if (err < 0)
12612 return err;
12613 err = alc861vd_auto_create_extra_out(spec,
12614 spec->autocfg.speaker_pins[0],
12615 "Speaker");
12616 if (err < 0)
12617 return err;
12618 err = alc861vd_auto_create_extra_out(spec,
12619 spec->autocfg.hp_pins[0],
12620 "Headphone");
12621 if (err < 0)
12622 return err;
12623 err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg);
12624 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012625 return err;
12626
12627 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
12628
12629 if (spec->autocfg.dig_out_pin)
12630 spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID;
12631
12632 if (spec->kctl_alloc)
12633 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
12634
12635 spec->init_verbs[spec->num_init_verbs++]
12636 = alc861vd_volume_init_verbs;
12637
12638 spec->num_mux_defs = 1;
12639 spec->input_mux = &spec->private_imux;
12640
Takashi Iwai776e1842007-08-29 15:07:11 +020012641 err = alc_auto_add_mic_boost(codec);
12642 if (err < 0)
12643 return err;
12644
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012645 return 1;
12646}
12647
12648/* additional initialization for auto-configuration model */
12649static void alc861vd_auto_init(struct hda_codec *codec)
12650{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012651 struct alc_spec *spec = codec->spec;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012652 alc861vd_auto_init_multi_out(codec);
12653 alc861vd_auto_init_hp_out(codec);
12654 alc861vd_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012655 if (spec->unsol_event)
12656 alc_sku_automute(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012657}
12658
12659static int patch_alc861vd(struct hda_codec *codec)
12660{
12661 struct alc_spec *spec;
12662 int err, board_config;
12663
12664 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
12665 if (spec == NULL)
12666 return -ENOMEM;
12667
12668 codec->spec = spec;
12669
12670 board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
12671 alc861vd_models,
12672 alc861vd_cfg_tbl);
12673
12674 if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
12675 printk(KERN_INFO "hda_codec: Unknown model for ALC660VD/"
12676 "ALC861VD, trying auto-probe from BIOS...\n");
12677 board_config = ALC861VD_AUTO;
12678 }
12679
12680 if (board_config == ALC861VD_AUTO) {
12681 /* automatic parse from the BIOS config */
12682 err = alc861vd_parse_auto_config(codec);
12683 if (err < 0) {
12684 alc_free(codec);
12685 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012686 } else if (!err) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012687 printk(KERN_INFO
12688 "hda_codec: Cannot set up configuration "
12689 "from BIOS. Using base mode...\n");
12690 board_config = ALC861VD_3ST;
12691 }
12692 }
12693
12694 if (board_config != ALC861VD_AUTO)
12695 setup_preset(spec, &alc861vd_presets[board_config]);
12696
12697 spec->stream_name_analog = "ALC861VD Analog";
12698 spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
12699 spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
12700
12701 spec->stream_name_digital = "ALC861VD Digital";
12702 spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
12703 spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
12704
12705 spec->adc_nids = alc861vd_adc_nids;
12706 spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
Takashi Iwaie1406342008-02-11 18:32:32 +010012707 spec->capsrc_nids = alc861vd_capsrc_nids;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012708
12709 spec->mixers[spec->num_mixers] = alc861vd_capture_mixer;
12710 spec->num_mixers++;
12711
Takashi Iwai2134ea42008-01-10 16:53:55 +010012712 spec->vmaster_nid = 0x02;
12713
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012714 codec->patch_ops = alc_patch_ops;
12715
12716 if (board_config == ALC861VD_AUTO)
12717 spec->init_hook = alc861vd_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020012718#ifdef CONFIG_SND_HDA_POWER_SAVE
12719 if (!spec->loopback.amplist)
12720 spec->loopback.amplist = alc861vd_loopbacks;
12721#endif
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012722
12723 return 0;
12724}
12725
12726/*
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012727 * ALC662 support
12728 *
12729 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
12730 * configuration. Each pin widget can choose any input DACs and a mixer.
12731 * Each ADC is connected from a mixer of all inputs. This makes possible
12732 * 6-channel independent captures.
12733 *
12734 * In addition, an independent DAC for the multi-playback (not used in this
12735 * driver yet).
12736 */
12737#define ALC662_DIGOUT_NID 0x06
12738#define ALC662_DIGIN_NID 0x0a
12739
12740static hda_nid_t alc662_dac_nids[4] = {
12741 /* front, rear, clfe, rear_surr */
12742 0x02, 0x03, 0x04
12743};
12744
12745static hda_nid_t alc662_adc_nids[1] = {
12746 /* ADC1-2 */
12747 0x09,
12748};
Takashi Iwaie1406342008-02-11 18:32:32 +010012749
12750static hda_nid_t alc662_capsrc_nids[1] = { 0x23 };
12751
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012752/* input MUX */
12753/* FIXME: should be a matrix-type input source selection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012754static struct hda_input_mux alc662_capture_source = {
12755 .num_items = 4,
12756 .items = {
12757 { "Mic", 0x0 },
12758 { "Front Mic", 0x1 },
12759 { "Line", 0x2 },
12760 { "CD", 0x4 },
12761 },
12762};
12763
12764static struct hda_input_mux alc662_lenovo_101e_capture_source = {
12765 .num_items = 2,
12766 .items = {
12767 { "Mic", 0x1 },
12768 { "Line", 0x2 },
12769 },
12770};
Kailang Yang291702f2007-10-16 14:28:03 +020012771
12772static struct hda_input_mux alc662_eeepc_capture_source = {
12773 .num_items = 2,
12774 .items = {
12775 { "i-Mic", 0x1 },
12776 { "e-Mic", 0x0 },
12777 },
12778};
12779
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012780#define alc662_mux_enum_info alc_mux_enum_info
12781#define alc662_mux_enum_get alc_mux_enum_get
Takashi Iwaie1406342008-02-11 18:32:32 +010012782#define alc662_mux_enum_put alc882_mux_enum_put
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012783
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012784/*
12785 * 2ch mode
12786 */
12787static struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
12788 { 2, NULL }
12789};
12790
12791/*
12792 * 2ch mode
12793 */
12794static struct hda_verb alc662_3ST_ch2_init[] = {
12795 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
12796 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
12797 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
12798 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
12799 { } /* end */
12800};
12801
12802/*
12803 * 6ch mode
12804 */
12805static struct hda_verb alc662_3ST_ch6_init[] = {
12806 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12807 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12808 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
12809 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12810 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12811 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
12812 { } /* end */
12813};
12814
12815static struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
12816 { 2, alc662_3ST_ch2_init },
12817 { 6, alc662_3ST_ch6_init },
12818};
12819
12820/*
12821 * 2ch mode
12822 */
12823static struct hda_verb alc662_sixstack_ch6_init[] = {
12824 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12825 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12826 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12827 { } /* end */
12828};
12829
12830/*
12831 * 6ch mode
12832 */
12833static struct hda_verb alc662_sixstack_ch8_init[] = {
12834 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12835 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12836 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12837 { } /* end */
12838};
12839
12840static struct hda_channel_mode alc662_5stack_modes[2] = {
12841 { 2, alc662_sixstack_ch6_init },
12842 { 6, alc662_sixstack_ch8_init },
12843};
12844
12845/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
12846 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
12847 */
12848
12849static struct snd_kcontrol_new alc662_base_mixer[] = {
12850 /* output mixer control */
12851 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12852 HDA_CODEC_MUTE("Front Playback Switch", 0x02, 0x0, HDA_OUTPUT),
12853 HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12854 HDA_CODEC_MUTE("Surround Playback Switch", 0x03, 0x0, HDA_OUTPUT),
12855 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
12856 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
12857 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT),
12858 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT),
12859 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
12860
12861 /*Input mixer control */
12862 HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
12863 HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
12864 HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
12865 HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
12866 HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
12867 HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
12868 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
12869 HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012870 { } /* end */
12871};
12872
12873static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
12874 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12875 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
12876 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
12877 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
12878 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
12879 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
12880 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
12881 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12882 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12883 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12884 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
12885 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
12886 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012887 { } /* end */
12888};
12889
12890static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
12891 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12892 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
12893 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
12894 HDA_BIND_MUTE("Surround Playback Switch", 0x03, 2, HDA_INPUT),
12895 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
12896 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
12897 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT),
12898 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT),
12899 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
12900 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
12901 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
12902 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
12903 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
12904 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12905 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12906 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12907 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
12908 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
12909 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012910 { } /* end */
12911};
12912
12913static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
12914 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12915 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010012916 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
12917 HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012918 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
12919 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
12920 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
12921 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12922 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012923 { } /* end */
12924};
12925
Kailang Yang291702f2007-10-16 14:28:03 +020012926static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +010012927 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020012928
Herton Ronaldo Krzesinskib4818492008-02-23 11:34:12 +010012929 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12930 HDA_CODEC_MUTE("Line-Out Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020012931
12932 HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT),
12933 HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12934 HDA_CODEC_MUTE("e-Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12935
12936 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
12937 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12938 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
12939 { } /* end */
12940};
12941
Kailang Yang8c427222008-01-10 13:03:59 +010012942static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
Takashi Iwai31bffaa2008-02-27 16:10:44 +010012943 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12944 HDA_CODEC_MUTE("Line-Out Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010012945 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
12946 HDA_BIND_MUTE("Surround Playback Switch", 0x03, 2, HDA_INPUT),
12947 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
12948 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
12949 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT),
12950 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010012951 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010012952 HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
12953 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
12954 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
12955 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12956 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12957 { } /* end */
12958};
12959
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012960static struct snd_kcontrol_new alc662_chmode_mixer[] = {
12961 {
12962 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12963 .name = "Channel Mode",
12964 .info = alc_ch_mode_info,
12965 .get = alc_ch_mode_get,
12966 .put = alc_ch_mode_put,
12967 },
12968 { } /* end */
12969};
12970
12971static struct hda_verb alc662_init_verbs[] = {
12972 /* ADC: mute amp left and right */
12973 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12974 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12975 /* Front mixer: unmute input/output amp left and right (volume = 0) */
12976
Takashi Iwaicb53c622007-08-10 17:21:45 +020012977 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12978 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12979 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12980 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12981 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012982
Kailang Yangb60dd392007-09-20 12:50:29 +020012983 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12984 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12985 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12986 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12987 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12988 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012989
12990 /* Front Pin: output 0 (0x0c) */
12991 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12992 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12993
12994 /* Rear Pin: output 1 (0x0d) */
12995 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12996 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12997
12998 /* CLFE Pin: output 2 (0x0e) */
12999 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13000 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13001
13002 /* Mic (rear) pin: input vref at 80% */
13003 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13004 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13005 /* Front Mic pin: input vref at 80% */
13006 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13007 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13008 /* Line In pin: input */
13009 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13010 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13011 /* Line-2 In: Headphone output (output 0 - 0x0c) */
13012 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13013 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13014 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
13015 /* CD pin widget for input */
13016 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13017
13018 /* FIXME: use matrix-type input source selection */
13019 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
13020 /* Input mixer */
13021 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13022 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13023 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13024 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Kailang Yang291702f2007-10-16 14:28:03 +020013025
13026 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13027 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13028 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13029 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013030 { }
13031};
13032
13033static struct hda_verb alc662_sue_init_verbs[] = {
13034 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
13035 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
Kailang Yang291702f2007-10-16 14:28:03 +020013036 {}
13037};
13038
13039static struct hda_verb alc662_eeepc_sue_init_verbs[] = {
13040 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13041 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
13042 {}
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013043};
13044
Kailang Yang8c427222008-01-10 13:03:59 +010013045/* Set Unsolicited Event*/
13046static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
13047 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13048 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
13049 {}
13050};
13051
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013052/*
13053 * generic initialization of ADC, input mixers and output mixers
13054 */
13055static struct hda_verb alc662_auto_init_verbs[] = {
13056 /*
13057 * Unmute ADC and set the default input to mic-in
13058 */
13059 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
13060 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13061
13062 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
13063 * mixer widget
13064 * Note: PASD motherboards uses the Line In 2 as the input for front
13065 * panel mic (mic 2)
13066 */
13067 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020013068 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13069 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13070 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
13071 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
13072 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013073
13074 /*
13075 * Set up output mixers (0x0c - 0x0f)
13076 */
13077 /* set vol=0 to output mixers */
13078 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13079 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13080 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13081
13082 /* set up input amps for analog loopback */
13083 /* Amp Indices: DAC = 0, mixer = 1 */
Kailang Yangb60dd392007-09-20 12:50:29 +020013084 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13085 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13086 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13087 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13088 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13089 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013090
13091
13092 /* FIXME: use matrix-type input source selection */
13093 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
13094 /* Input mixer */
13095 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangd1a991a2007-08-15 16:21:59 +020013096 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013097 { }
13098};
13099
13100/* capture mixer elements */
13101static struct snd_kcontrol_new alc662_capture_mixer[] = {
13102 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
13103 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
13104 {
13105 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13106 /* The multiple "Capture Source" controls confuse alsamixer
13107 * So call somewhat different..
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013108 */
13109 /* .name = "Capture Source", */
13110 .name = "Input Source",
13111 .count = 1,
Herton Ronaldo Krzesinski6e7939b2007-12-19 17:49:02 +010013112 .info = alc662_mux_enum_info,
13113 .get = alc662_mux_enum_get,
13114 .put = alc662_mux_enum_put,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013115 },
13116 { } /* end */
13117};
13118
13119static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
13120{
13121 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013122 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013123
13124 present = snd_hda_codec_read(codec, 0x14, 0,
13125 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020013126 bits = present ? HDA_AMP_MUTE : 0;
13127 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
13128 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013129}
13130
13131static void alc662_lenovo_101e_all_automute(struct hda_codec *codec)
13132{
13133 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013134 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013135
13136 present = snd_hda_codec_read(codec, 0x1b, 0,
13137 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020013138 bits = present ? HDA_AMP_MUTE : 0;
13139 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
13140 HDA_AMP_MUTE, bits);
13141 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
13142 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013143}
13144
13145static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec,
13146 unsigned int res)
13147{
13148 if ((res >> 26) == ALC880_HP_EVENT)
13149 alc662_lenovo_101e_all_automute(codec);
13150 if ((res >> 26) == ALC880_FRONT_EVENT)
13151 alc662_lenovo_101e_ispeaker_automute(codec);
13152}
13153
Kailang Yang291702f2007-10-16 14:28:03 +020013154static void alc662_eeepc_mic_automute(struct hda_codec *codec)
13155{
13156 unsigned int present;
13157
13158 present = snd_hda_codec_read(codec, 0x18, 0,
13159 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
13160 snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
13161 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
13162 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
13163 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
13164 snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
13165 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
13166 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
13167 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
13168}
13169
13170/* unsolicited event for HP jack sensing */
13171static void alc662_eeepc_unsol_event(struct hda_codec *codec,
13172 unsigned int res)
13173{
13174 if ((res >> 26) == ALC880_HP_EVENT)
13175 alc262_hippo1_automute( codec );
13176
13177 if ((res >> 26) == ALC880_MIC_EVENT)
13178 alc662_eeepc_mic_automute(codec);
13179}
13180
13181static void alc662_eeepc_inithook(struct hda_codec *codec)
13182{
13183 alc262_hippo1_automute( codec );
13184 alc662_eeepc_mic_automute(codec);
13185}
13186
Kailang Yang8c427222008-01-10 13:03:59 +010013187static void alc662_eeepc_ep20_automute(struct hda_codec *codec)
13188{
13189 unsigned int mute;
13190 unsigned int present;
13191
13192 snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
13193 present = snd_hda_codec_read(codec, 0x14, 0,
13194 AC_VERB_GET_PIN_SENSE, 0);
13195 present = (present & 0x80000000) != 0;
13196 if (present) {
13197 /* mute internal speaker */
13198 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
13199 HDA_AMP_MUTE, HDA_AMP_MUTE);
13200 } else {
13201 /* unmute internal speaker if necessary */
13202 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
13203 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
13204 HDA_AMP_MUTE, mute);
13205 }
13206}
13207
13208/* unsolicited event for HP jack sensing */
13209static void alc662_eeepc_ep20_unsol_event(struct hda_codec *codec,
13210 unsigned int res)
13211{
13212 if ((res >> 26) == ALC880_HP_EVENT)
13213 alc662_eeepc_ep20_automute(codec);
13214}
13215
13216static void alc662_eeepc_ep20_inithook(struct hda_codec *codec)
13217{
13218 alc662_eeepc_ep20_automute(codec);
13219}
13220
Takashi Iwaicb53c622007-08-10 17:21:45 +020013221#ifdef CONFIG_SND_HDA_POWER_SAVE
13222#define alc662_loopbacks alc880_loopbacks
13223#endif
13224
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013225
13226/* pcm configuration: identiacal with ALC880 */
13227#define alc662_pcm_analog_playback alc880_pcm_analog_playback
13228#define alc662_pcm_analog_capture alc880_pcm_analog_capture
13229#define alc662_pcm_digital_playback alc880_pcm_digital_playback
13230#define alc662_pcm_digital_capture alc880_pcm_digital_capture
13231
13232/*
13233 * configuration and preset
13234 */
13235static const char *alc662_models[ALC662_MODEL_LAST] = {
13236 [ALC662_3ST_2ch_DIG] = "3stack-dig",
13237 [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
13238 [ALC662_3ST_6ch] = "3stack-6ch",
13239 [ALC662_5ST_DIG] = "6stack-dig",
13240 [ALC662_LENOVO_101E] = "lenovo-101e",
Takashi Iwaib995d762007-10-17 10:41:06 +020013241 [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
Kailang Yang8c427222008-01-10 13:03:59 +010013242 [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013243 [ALC662_AUTO] = "auto",
13244};
13245
13246static struct snd_pci_quirk alc662_cfg_tbl[] = {
Kailang Yang291702f2007-10-16 14:28:03 +020013247 SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
Kailang Yang8c427222008-01-10 13:03:59 +010013248 SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013249 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013250 {}
13251};
13252
13253static struct alc_config_preset alc662_presets[] = {
13254 [ALC662_3ST_2ch_DIG] = {
Kailang Yang291702f2007-10-16 14:28:03 +020013255 .mixers = { alc662_3ST_2ch_mixer, alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013256 .init_verbs = { alc662_init_verbs },
13257 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13258 .dac_nids = alc662_dac_nids,
13259 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013260 .dig_in_nid = ALC662_DIGIN_NID,
13261 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
13262 .channel_mode = alc662_3ST_2ch_modes,
13263 .input_mux = &alc662_capture_source,
13264 },
13265 [ALC662_3ST_6ch_DIG] = {
Kailang Yang291702f2007-10-16 14:28:03 +020013266 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer,
13267 alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013268 .init_verbs = { alc662_init_verbs },
13269 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13270 .dac_nids = alc662_dac_nids,
13271 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013272 .dig_in_nid = ALC662_DIGIN_NID,
13273 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
13274 .channel_mode = alc662_3ST_6ch_modes,
13275 .need_dac_fix = 1,
13276 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013277 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013278 [ALC662_3ST_6ch] = {
Kailang Yang291702f2007-10-16 14:28:03 +020013279 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer,
13280 alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013281 .init_verbs = { alc662_init_verbs },
13282 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13283 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013284 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
13285 .channel_mode = alc662_3ST_6ch_modes,
13286 .need_dac_fix = 1,
13287 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013288 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013289 [ALC662_5ST_DIG] = {
Kailang Yang291702f2007-10-16 14:28:03 +020013290 .mixers = { alc662_base_mixer, alc662_chmode_mixer,
13291 alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013292 .init_verbs = { alc662_init_verbs },
13293 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13294 .dac_nids = alc662_dac_nids,
13295 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013296 .dig_in_nid = ALC662_DIGIN_NID,
13297 .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
13298 .channel_mode = alc662_5stack_modes,
13299 .input_mux = &alc662_capture_source,
13300 },
13301 [ALC662_LENOVO_101E] = {
Kailang Yang291702f2007-10-16 14:28:03 +020013302 .mixers = { alc662_lenovo_101e_mixer, alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013303 .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
13304 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13305 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013306 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
13307 .channel_mode = alc662_3ST_2ch_modes,
13308 .input_mux = &alc662_lenovo_101e_capture_source,
13309 .unsol_event = alc662_lenovo_101e_unsol_event,
13310 .init_hook = alc662_lenovo_101e_all_automute,
13311 },
Kailang Yang291702f2007-10-16 14:28:03 +020013312 [ALC662_ASUS_EEEPC_P701] = {
13313 .mixers = { alc662_eeepc_p701_mixer, alc662_capture_mixer },
13314 .init_verbs = { alc662_init_verbs,
13315 alc662_eeepc_sue_init_verbs },
13316 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13317 .dac_nids = alc662_dac_nids,
Kailang Yang291702f2007-10-16 14:28:03 +020013318 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
13319 .channel_mode = alc662_3ST_2ch_modes,
13320 .input_mux = &alc662_eeepc_capture_source,
13321 .unsol_event = alc662_eeepc_unsol_event,
13322 .init_hook = alc662_eeepc_inithook,
13323 },
Kailang Yang8c427222008-01-10 13:03:59 +010013324 [ALC662_ASUS_EEEPC_EP20] = {
13325 .mixers = { alc662_eeepc_ep20_mixer, alc662_capture_mixer,
13326 alc662_chmode_mixer },
13327 .init_verbs = { alc662_init_verbs,
13328 alc662_eeepc_ep20_sue_init_verbs },
13329 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13330 .dac_nids = alc662_dac_nids,
Kailang Yang8c427222008-01-10 13:03:59 +010013331 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
13332 .channel_mode = alc662_3ST_6ch_modes,
13333 .input_mux = &alc662_lenovo_101e_capture_source,
13334 .unsol_event = alc662_eeepc_ep20_unsol_event,
13335 .init_hook = alc662_eeepc_ep20_inithook,
13336 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013337
13338};
13339
13340
13341/*
13342 * BIOS auto configuration
13343 */
13344
13345/* add playback controls from the parsed DAC table */
13346static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec,
13347 const struct auto_pin_cfg *cfg)
13348{
13349 char name[32];
13350 static const char *chname[4] = {
13351 "Front", "Surround", NULL /*CLFE*/, "Side"
13352 };
13353 hda_nid_t nid;
13354 int i, err;
13355
13356 for (i = 0; i < cfg->line_outs; i++) {
13357 if (!spec->multiout.dac_nids[i])
13358 continue;
Kailang Yangb60dd392007-09-20 12:50:29 +020013359 nid = alc880_idx_to_dac(i);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013360 if (i == 2) {
13361 /* Center/LFE */
13362 err = add_control(spec, ALC_CTL_WIDGET_VOL,
13363 "Center Playback Volume",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013364 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
13365 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013366 if (err < 0)
13367 return err;
13368 err = add_control(spec, ALC_CTL_WIDGET_VOL,
13369 "LFE Playback Volume",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013370 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
13371 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013372 if (err < 0)
13373 return err;
13374 err = add_control(spec, ALC_CTL_BIND_MUTE,
13375 "Center Playback Switch",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013376 HDA_COMPOSE_AMP_VAL(nid, 1, 2,
13377 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013378 if (err < 0)
13379 return err;
13380 err = add_control(spec, ALC_CTL_BIND_MUTE,
13381 "LFE Playback Switch",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013382 HDA_COMPOSE_AMP_VAL(nid, 2, 2,
13383 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013384 if (err < 0)
13385 return err;
13386 } else {
13387 sprintf(name, "%s Playback Volume", chname[i]);
13388 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013389 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
13390 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013391 if (err < 0)
13392 return err;
13393 sprintf(name, "%s Playback Switch", chname[i]);
13394 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013395 HDA_COMPOSE_AMP_VAL(nid, 3, 2,
13396 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013397 if (err < 0)
13398 return err;
13399 }
13400 }
13401 return 0;
13402}
13403
13404/* add playback controls for speaker and HP outputs */
13405static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
13406 const char *pfx)
13407{
13408 hda_nid_t nid;
13409 int err;
13410 char name[32];
13411
13412 if (!pin)
13413 return 0;
13414
13415 if (alc880_is_fixed_pin(pin)) {
13416 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
13417 /* printk("DAC nid=%x\n",nid); */
13418 /* specify the DAC as the extra output */
13419 if (!spec->multiout.hp_nid)
13420 spec->multiout.hp_nid = nid;
13421 else
13422 spec->multiout.extra_out_nid[0] = nid;
13423 /* control HP volume/switch on the output mixer amp */
13424 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
13425 sprintf(name, "%s Playback Volume", pfx);
13426 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
13427 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
13428 if (err < 0)
13429 return err;
13430 sprintf(name, "%s Playback Switch", pfx);
13431 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
13432 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
13433 if (err < 0)
13434 return err;
13435 } else if (alc880_is_multi_pin(pin)) {
13436 /* set manual connection */
13437 /* we have only a switch on HP-out PIN */
13438 sprintf(name, "%s Playback Switch", pfx);
13439 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
13440 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
13441 if (err < 0)
13442 return err;
13443 }
13444 return 0;
13445}
13446
13447/* create playback/capture controls for input pins */
13448static int alc662_auto_create_analog_input_ctls(struct alc_spec *spec,
13449 const struct auto_pin_cfg *cfg)
13450{
13451 struct hda_input_mux *imux = &spec->private_imux;
13452 int i, err, idx;
13453
13454 for (i = 0; i < AUTO_PIN_LAST; i++) {
13455 if (alc880_is_input_pin(cfg->input_pins[i])) {
13456 idx = alc880_input_pin_idx(cfg->input_pins[i]);
13457 err = new_analog_input(spec, cfg->input_pins[i],
13458 auto_pin_cfg_labels[i],
13459 idx, 0x0b);
13460 if (err < 0)
13461 return err;
13462 imux->items[imux->num_items].label =
13463 auto_pin_cfg_labels[i];
13464 imux->items[imux->num_items].index =
13465 alc880_input_pin_idx(cfg->input_pins[i]);
13466 imux->num_items++;
13467 }
13468 }
13469 return 0;
13470}
13471
13472static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
13473 hda_nid_t nid, int pin_type,
13474 int dac_idx)
13475{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013476 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013477 /* need the manual connection? */
13478 if (alc880_is_multi_pin(nid)) {
13479 struct alc_spec *spec = codec->spec;
13480 int idx = alc880_multi_pin_idx(nid);
13481 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
13482 AC_VERB_SET_CONNECT_SEL,
13483 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
13484 }
13485}
13486
13487static void alc662_auto_init_multi_out(struct hda_codec *codec)
13488{
13489 struct alc_spec *spec = codec->spec;
13490 int i;
13491
Kailang Yang8c427222008-01-10 13:03:59 +010013492 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013493 for (i = 0; i <= HDA_SIDE; i++) {
13494 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020013495 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013496 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020013497 alc662_auto_set_output_and_unmute(codec, nid, pin_type,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013498 i);
13499 }
13500}
13501
13502static void alc662_auto_init_hp_out(struct hda_codec *codec)
13503{
13504 struct alc_spec *spec = codec->spec;
13505 hda_nid_t pin;
13506
13507 pin = spec->autocfg.hp_pins[0];
13508 if (pin) /* connect to front */
13509 /* use dac 0 */
13510 alc662_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013511 pin = spec->autocfg.speaker_pins[0];
13512 if (pin)
13513 alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013514}
13515
13516#define alc662_is_input_pin(nid) alc880_is_input_pin(nid)
13517#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID
13518
13519static void alc662_auto_init_analog_input(struct hda_codec *codec)
13520{
13521 struct alc_spec *spec = codec->spec;
13522 int i;
13523
13524 for (i = 0; i < AUTO_PIN_LAST; i++) {
13525 hda_nid_t nid = spec->autocfg.input_pins[i];
13526 if (alc662_is_input_pin(nid)) {
13527 snd_hda_codec_write(codec, nid, 0,
13528 AC_VERB_SET_PIN_WIDGET_CONTROL,
13529 (i <= AUTO_PIN_FRONT_MIC ?
13530 PIN_VREF80 : PIN_IN));
13531 if (nid != ALC662_PIN_CD_NID)
13532 snd_hda_codec_write(codec, nid, 0,
13533 AC_VERB_SET_AMP_GAIN_MUTE,
13534 AMP_OUT_MUTE);
13535 }
13536 }
13537}
13538
13539static int alc662_parse_auto_config(struct hda_codec *codec)
13540{
13541 struct alc_spec *spec = codec->spec;
13542 int err;
13543 static hda_nid_t alc662_ignore[] = { 0x1d, 0 };
13544
13545 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
13546 alc662_ignore);
13547 if (err < 0)
13548 return err;
13549 if (!spec->autocfg.line_outs)
13550 return 0; /* can't find valid BIOS pin config */
13551
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013552 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
13553 if (err < 0)
13554 return err;
13555 err = alc662_auto_create_multi_out_ctls(spec, &spec->autocfg);
13556 if (err < 0)
13557 return err;
13558 err = alc662_auto_create_extra_out(spec,
13559 spec->autocfg.speaker_pins[0],
13560 "Speaker");
13561 if (err < 0)
13562 return err;
13563 err = alc662_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
13564 "Headphone");
13565 if (err < 0)
13566 return err;
13567 err = alc662_auto_create_analog_input_ctls(spec, &spec->autocfg);
13568 if (err < 0)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013569 return err;
13570
13571 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
13572
13573 if (spec->autocfg.dig_out_pin)
13574 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
13575
13576 if (spec->kctl_alloc)
13577 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
13578
13579 spec->num_mux_defs = 1;
13580 spec->input_mux = &spec->private_imux;
13581
Takashi Iwai8c872862007-06-19 12:11:16 +020013582 spec->init_verbs[spec->num_init_verbs++] = alc662_auto_init_verbs;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013583 spec->mixers[spec->num_mixers] = alc662_capture_mixer;
13584 spec->num_mixers++;
Takashi Iwai8c872862007-06-19 12:11:16 +020013585 return 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013586}
13587
13588/* additional initialization for auto-configuration model */
13589static void alc662_auto_init(struct hda_codec *codec)
13590{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013591 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013592 alc662_auto_init_multi_out(codec);
13593 alc662_auto_init_hp_out(codec);
13594 alc662_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013595 if (spec->unsol_event)
13596 alc_sku_automute(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013597}
13598
13599static int patch_alc662(struct hda_codec *codec)
13600{
13601 struct alc_spec *spec;
13602 int err, board_config;
13603
13604 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
13605 if (!spec)
13606 return -ENOMEM;
13607
13608 codec->spec = spec;
13609
13610 board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
13611 alc662_models,
13612 alc662_cfg_tbl);
13613 if (board_config < 0) {
13614 printk(KERN_INFO "hda_codec: Unknown model for ALC662, "
13615 "trying auto-probe from BIOS...\n");
13616 board_config = ALC662_AUTO;
13617 }
13618
13619 if (board_config == ALC662_AUTO) {
13620 /* automatic parse from the BIOS config */
13621 err = alc662_parse_auto_config(codec);
13622 if (err < 0) {
13623 alc_free(codec);
13624 return err;
Takashi Iwai8c872862007-06-19 12:11:16 +020013625 } else if (!err) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013626 printk(KERN_INFO
13627 "hda_codec: Cannot set up configuration "
13628 "from BIOS. Using base mode...\n");
13629 board_config = ALC662_3ST_2ch_DIG;
13630 }
13631 }
13632
13633 if (board_config != ALC662_AUTO)
13634 setup_preset(spec, &alc662_presets[board_config]);
13635
13636 spec->stream_name_analog = "ALC662 Analog";
13637 spec->stream_analog_playback = &alc662_pcm_analog_playback;
13638 spec->stream_analog_capture = &alc662_pcm_analog_capture;
13639
13640 spec->stream_name_digital = "ALC662 Digital";
13641 spec->stream_digital_playback = &alc662_pcm_digital_playback;
13642 spec->stream_digital_capture = &alc662_pcm_digital_capture;
13643
Takashi Iwaie1406342008-02-11 18:32:32 +010013644 spec->adc_nids = alc662_adc_nids;
13645 spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
13646 spec->capsrc_nids = alc662_capsrc_nids;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013647
Takashi Iwai2134ea42008-01-10 16:53:55 +010013648 spec->vmaster_nid = 0x02;
13649
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013650 codec->patch_ops = alc_patch_ops;
13651 if (board_config == ALC662_AUTO)
13652 spec->init_hook = alc662_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020013653#ifdef CONFIG_SND_HDA_POWER_SAVE
13654 if (!spec->loopback.amplist)
13655 spec->loopback.amplist = alc662_loopbacks;
13656#endif
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013657
13658 return 0;
13659}
13660
13661/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070013662 * patch entries
13663 */
13664struct hda_codec_preset snd_hda_preset_realtek[] = {
13665 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +010013666 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +010013667 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +020013668 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +010013669 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013670 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013671 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013672 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
13673 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
13674 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013675 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
13676 .patch = patch_alc883 },
13677 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
13678 .patch = patch_alc662 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013679 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070013680 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013681 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 },
Kailang Yangdf694da2005-12-05 19:42:22 +010013682 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013683 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 },
Kailang Yangf6a92242007-12-13 16:52:54 +010013684 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc883 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070013685 {} /* terminator */
13686};