blob: d41eafacd86deecd224d6052d0113a0b58a75155 [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 Iwaic8b6bf9b2005-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 Iwaic8b6bf9b2005-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 Iwaic8b6bf9b2005-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 Iwaic8b6bf9b2005-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 Iwaic8b6bf9b2005-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 Iwaic8b6bf9b2005-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 Iwaic8b6bf9b2005-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 Iwaic8b6bf9b2005-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 Iwaic8b6bf9b2005-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 Iwaic8b6bf9b2005-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 Iwaic8b6bf9b2005-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 Iwaic8b6bf9b2005-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;
1523 }
1524 if (spec->dig_in_nid) {
1525 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
1526 if (err < 0)
1527 return err;
1528 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01001529
1530 /* if we have no master control, let's create it */
1531 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
1532 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
1533 HDA_OUTPUT, spec->vmaster_tlv);
1534 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
1535 spec->vmaster_tlv, alc_slave_vols);
1536 if (err < 0)
1537 return err;
1538 }
1539 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
1540 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
1541 NULL, alc_slave_sws);
1542 if (err < 0)
1543 return err;
1544 }
1545
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 return 0;
1547}
1548
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001549
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550/*
1551 * initialize the codec volumes, etc
1552 */
1553
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001554/*
1555 * generic initialization of ADC, input mixers and output mixers
1556 */
1557static struct hda_verb alc880_volume_init_verbs[] = {
1558 /*
1559 * Unmute ADC0-2 and set the default input to mic-in
1560 */
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001561 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001562 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001563 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001564 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001565 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001566 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001568 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
1569 * mixer widget
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001570 * Note: PASD motherboards uses the Line In 2 as the input for front
1571 * panel mic (mic 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001573 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02001574 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1575 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1576 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
1577 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
1578 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
1579 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
1580 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001582 /*
1583 * Set up output mixers (0x0c - 0x0f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001585 /* set vol=0 to output mixers */
1586 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1587 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1588 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1589 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1590 /* set up input amps for analog loopback */
1591 /* Amp Indices: DAC = 0, mixer = 1 */
Takashi Iwai05acb862005-06-10 19:50:25 +02001592 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1593 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02001594 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1595 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02001596 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1597 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02001598 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1599 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600
1601 { }
1602};
1603
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001604/*
1605 * 3-stack pin configuration:
1606 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
1607 */
1608static struct hda_verb alc880_pin_3stack_init_verbs[] = {
1609 /*
1610 * preset connection lists of input pins
1611 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
1612 */
1613 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
1614 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1615 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
1616
1617 /*
1618 * Set pin mode and muting
1619 */
1620 /* set front pin widgets 0x14 for output */
1621 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1622 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1623 /* Mic1 (rear panel) pin widget for input and vref at 80% */
1624 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1625 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1626 /* Mic2 (as headphone out) for HP output */
1627 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1628 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1629 /* Line In pin widget for input */
1630 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1631 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1632 /* Line2 (as front mic) pin widget for input and vref at 80% */
1633 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1634 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1635 /* CD pin widget for input */
1636 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1637
1638 { }
1639};
1640
1641/*
1642 * 5-stack pin configuration:
1643 * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
1644 * line-in/side = 0x1a, f-mic = 0x1b
1645 */
1646static struct hda_verb alc880_pin_5stack_init_verbs[] = {
1647 /*
1648 * preset connection lists of input pins
1649 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
1650 */
1651 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1652 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
1653
1654 /*
1655 * Set pin mode and muting
1656 */
1657 /* set pin widgets 0x14-0x17 for output */
Takashi Iwai05acb862005-06-10 19:50:25 +02001658 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1659 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1660 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1661 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001662 /* unmute pins for output (no gain on this amp) */
1663 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1664 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1665 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1666 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1667
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02001669 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001670 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1671 /* Mic2 (as headphone out) for HP output */
1672 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02001673 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001674 /* Line In pin widget for input */
1675 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1676 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1677 /* Line2 (as front mic) pin widget for input and vref at 80% */
1678 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1679 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1680 /* CD pin widget for input */
1681 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682
1683 { }
1684};
1685
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001686/*
1687 * W810 pin configuration:
1688 * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
1689 */
1690static struct hda_verb alc880_pin_w810_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 /* hphone/speaker input selector: front DAC */
1692 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
1693
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001694 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1695 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1696 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1697 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1698 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1699 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1700
1701 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02001702 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 { }
1705};
1706
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001707/*
1708 * Z71V pin configuration:
1709 * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
1710 */
1711static struct hda_verb alc880_pin_z71v_init_verbs[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02001712 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001713 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai05acb862005-06-10 19:50:25 +02001714 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001715 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001716
Takashi Iwai16ded522005-06-10 19:58:24 +02001717 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001718 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02001719 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001720 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001721
1722 { }
1723};
1724
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001725/*
1726 * 6-stack pin configuration:
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001727 * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
1728 * f-mic = 0x19, line = 0x1a, HP = 0x1b
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001729 */
1730static struct hda_verb alc880_pin_6stack_init_verbs[] = {
1731 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1732
Takashi Iwai16ded522005-06-10 19:58:24 +02001733 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001734 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001735 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001736 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001737 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001738 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001739 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001740 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1741
Takashi Iwai16ded522005-06-10 19:58:24 +02001742 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001743 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001744 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001745 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001746 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001747 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001748 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai16ded522005-06-10 19:58:24 +02001749 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001750 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1751
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001752 { }
1753};
Takashi Iwai16ded522005-06-10 19:58:24 +02001754
Kailang Yangccc656c2006-10-17 12:32:26 +02001755/*
1756 * Uniwill pin configuration:
1757 * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
1758 * line = 0x1a
1759 */
1760static struct hda_verb alc880_uniwill_init_verbs[] = {
1761 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1762
1763 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1764 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1765 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1766 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1767 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1768 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1769 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1770 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1771 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1772 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1773 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1774 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1775 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1776 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1777
1778 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1779 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1780 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1781 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1782 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1783 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1784 /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
1785 /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
1786 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1787
1788 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
1789 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
1790
1791 { }
1792};
1793
1794/*
1795* Uniwill P53
1796* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
1797 */
1798static struct hda_verb alc880_uniwill_p53_init_verbs[] = {
1799 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1800
1801 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1802 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1803 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1804 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1805 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1806 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1807 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1808 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1809 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1810 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1811 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1812 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1813
1814 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1815 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1816 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1817 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1818 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1819 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1820
1821 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
1822 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT},
1823
1824 { }
1825};
1826
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01001827static struct hda_verb alc880_beep_init_verbs[] = {
1828 { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
1829 { }
1830};
1831
Kailang Yangccc656c2006-10-17 12:32:26 +02001832/* toggle speaker-output according to the hp-jack state */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02001833static void alc880_uniwill_hp_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02001834{
1835 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001836 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02001837
1838 present = snd_hda_codec_read(codec, 0x14, 0,
1839 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02001840 bits = present ? HDA_AMP_MUTE : 0;
1841 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
1842 HDA_AMP_MUTE, bits);
1843 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
1844 HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02001845}
1846
1847/* auto-toggle front mic */
1848static void alc880_uniwill_mic_automute(struct hda_codec *codec)
1849{
1850 unsigned int present;
1851 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02001852
1853 present = snd_hda_codec_read(codec, 0x18, 0,
1854 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02001855 bits = present ? HDA_AMP_MUTE : 0;
1856 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02001857}
1858
1859static void alc880_uniwill_automute(struct hda_codec *codec)
1860{
1861 alc880_uniwill_hp_automute(codec);
1862 alc880_uniwill_mic_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02001863}
1864
1865static void alc880_uniwill_unsol_event(struct hda_codec *codec,
1866 unsigned int res)
1867{
1868 /* Looks like the unsol event is incompatible with the standard
1869 * definition. 4bit tag is placed at 28 bit!
1870 */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02001871 switch (res >> 28) {
1872 case ALC880_HP_EVENT:
1873 alc880_uniwill_hp_automute(codec);
1874 break;
1875 case ALC880_MIC_EVENT:
1876 alc880_uniwill_mic_automute(codec);
1877 break;
1878 }
Kailang Yangccc656c2006-10-17 12:32:26 +02001879}
1880
1881static void alc880_uniwill_p53_hp_automute(struct hda_codec *codec)
1882{
1883 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001884 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02001885
1886 present = snd_hda_codec_read(codec, 0x14, 0,
1887 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02001888 bits = present ? HDA_AMP_MUTE : 0;
1889 snd_hda_codec_amp_stereo(codec, 0x15, HDA_INPUT, 0, HDA_AMP_MUTE, bits);
Kailang Yangccc656c2006-10-17 12:32:26 +02001890}
1891
1892static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
1893{
1894 unsigned int present;
1895
1896 present = snd_hda_codec_read(codec, 0x21, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02001897 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
1898 present &= HDA_AMP_VOLMASK;
1899 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0,
1900 HDA_AMP_VOLMASK, present);
1901 snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0,
1902 HDA_AMP_VOLMASK, present);
Kailang Yangccc656c2006-10-17 12:32:26 +02001903}
Takashi Iwai47fd8302007-08-10 17:11:07 +02001904
Kailang Yangccc656c2006-10-17 12:32:26 +02001905static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
1906 unsigned int res)
1907{
1908 /* Looks like the unsol event is incompatible with the standard
1909 * definition. 4bit tag is placed at 28 bit!
1910 */
1911 if ((res >> 28) == ALC880_HP_EVENT)
1912 alc880_uniwill_p53_hp_automute(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001913 if ((res >> 28) == ALC880_DCVOL_EVENT)
Kailang Yangccc656c2006-10-17 12:32:26 +02001914 alc880_uniwill_p53_dcvol_automute(codec);
1915}
1916
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001917/*
1918 * F1734 pin configuration:
1919 * HP = 0x14, speaker-out = 0x15, mic = 0x18
1920 */
1921static struct hda_verb alc880_pin_f1734_init_verbs[] = {
1922 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
1923 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
1924 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
1925 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
1926
1927 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1928 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1929 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1930 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1931
1932 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1933 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1934 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1935 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1936 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1937 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1938 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1939 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1940 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02001941
Takashi Iwai937b4162008-02-11 14:52:36 +01001942 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
1943 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_DCVOL_EVENT},
1944
Takashi Iwai16ded522005-06-10 19:58:24 +02001945 { }
1946};
1947
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001948/*
1949 * ASUS pin configuration:
1950 * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
1951 */
1952static struct hda_verb alc880_pin_asus_init_verbs[] = {
1953 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
1954 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
1955 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
1956 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
1957
1958 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1959 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1960 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1961 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1962 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1963 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1964 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1965 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1966
1967 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1968 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1969 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1970 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1971 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1972 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1973 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1974 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1975 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1976
1977 { }
1978};
1979
1980/* Enable GPIO mask and set output */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001981#define alc880_gpio1_init_verbs alc_gpio1_init_verbs
1982#define alc880_gpio2_init_verbs alc_gpio2_init_verbs
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001983
Kailang Yangdf694da2005-12-05 19:42:22 +01001984/* Clevo m520g init */
1985static struct hda_verb alc880_pin_clevo_init_verbs[] = {
1986 /* headphone output */
1987 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
1988 /* line-out */
1989 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1990 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1991 /* Line-in */
1992 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1993 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1994 /* CD */
1995 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1996 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1997 /* Mic1 (rear panel) */
1998 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1999 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2000 /* Mic2 (front panel) */
2001 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2002 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2003 /* headphone */
2004 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2005 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2006 /* change to EAPD mode */
2007 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2008 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2009
2010 { }
2011};
2012
2013static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02002014 /* change to EAPD mode */
2015 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2016 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2017
Kailang Yangdf694da2005-12-05 19:42:22 +01002018 /* Headphone output */
2019 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2020 /* Front output*/
2021 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2022 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
2023
2024 /* Line In pin widget for input */
2025 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2026 /* CD pin widget for input */
2027 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2028 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2029 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2030
2031 /* change to EAPD mode */
2032 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2033 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
2034
2035 { }
2036};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002037
2038/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002039 * LG m1 express dual
2040 *
2041 * Pin assignment:
2042 * Rear Line-In/Out (blue): 0x14
2043 * Build-in Mic-In: 0x15
2044 * Speaker-out: 0x17
2045 * HP-Out (green): 0x1b
2046 * Mic-In/Out (red): 0x19
2047 * SPDIF-Out: 0x1e
2048 */
2049
2050/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
2051static hda_nid_t alc880_lg_dac_nids[3] = {
2052 0x05, 0x02, 0x03
2053};
2054
2055/* seems analog CD is not working */
2056static struct hda_input_mux alc880_lg_capture_source = {
2057 .num_items = 3,
2058 .items = {
2059 { "Mic", 0x1 },
2060 { "Line", 0x5 },
2061 { "Internal Mic", 0x6 },
2062 },
2063};
2064
2065/* 2,4,6 channel modes */
2066static struct hda_verb alc880_lg_ch2_init[] = {
2067 /* set line-in and mic-in to input */
2068 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2069 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2070 { }
2071};
2072
2073static struct hda_verb alc880_lg_ch4_init[] = {
2074 /* set line-in to out and mic-in to input */
2075 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2076 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2077 { }
2078};
2079
2080static struct hda_verb alc880_lg_ch6_init[] = {
2081 /* set line-in and mic-in to output */
2082 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2083 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2084 { }
2085};
2086
2087static struct hda_channel_mode alc880_lg_ch_modes[3] = {
2088 { 2, alc880_lg_ch2_init },
2089 { 4, alc880_lg_ch4_init },
2090 { 6, alc880_lg_ch6_init },
2091};
2092
2093static struct snd_kcontrol_new alc880_lg_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002094 HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2095 HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002096 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2097 HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
2098 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
2099 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
2100 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
2101 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
2102 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2103 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
2104 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT),
2105 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT),
2106 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT),
2107 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT),
2108 {
2109 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2110 .name = "Channel Mode",
2111 .info = alc_ch_mode_info,
2112 .get = alc_ch_mode_get,
2113 .put = alc_ch_mode_put,
2114 },
2115 { } /* end */
2116};
2117
2118static struct hda_verb alc880_lg_init_verbs[] = {
2119 /* set capture source to mic-in */
2120 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2121 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2122 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2123 /* mute all amp mixer inputs */
2124 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02002125 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2126 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002127 /* line-in to input */
2128 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2129 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2130 /* built-in mic */
2131 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2132 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2133 /* speaker-out */
2134 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2135 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2136 /* mic-in to input */
2137 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
2138 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2139 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2140 /* HP-out */
2141 {0x13, AC_VERB_SET_CONNECT_SEL, 0x03},
2142 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2143 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2144 /* jack sense */
2145 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1},
2146 { }
2147};
2148
2149/* toggle speaker-output according to the hp-jack state */
2150static void alc880_lg_automute(struct hda_codec *codec)
2151{
2152 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002153 unsigned char bits;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002154
2155 present = snd_hda_codec_read(codec, 0x1b, 0,
2156 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002157 bits = present ? HDA_AMP_MUTE : 0;
2158 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
2159 HDA_AMP_MUTE, bits);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002160}
2161
2162static void alc880_lg_unsol_event(struct hda_codec *codec, unsigned int res)
2163{
2164 /* Looks like the unsol event is incompatible with the standard
2165 * definition. 4bit tag is placed at 28 bit!
2166 */
2167 if ((res >> 28) == 0x01)
2168 alc880_lg_automute(codec);
2169}
2170
2171/*
Takashi Iwaid6815182006-03-23 16:06:23 +01002172 * LG LW20
2173 *
2174 * Pin assignment:
2175 * Speaker-out: 0x14
2176 * Mic-In: 0x18
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002177 * Built-in Mic-In: 0x19
2178 * Line-In: 0x1b
2179 * HP-Out: 0x1a
Takashi Iwaid6815182006-03-23 16:06:23 +01002180 * SPDIF-Out: 0x1e
2181 */
2182
Takashi Iwaid6815182006-03-23 16:06:23 +01002183static struct hda_input_mux alc880_lg_lw_capture_source = {
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002184 .num_items = 3,
Takashi Iwaid6815182006-03-23 16:06:23 +01002185 .items = {
2186 { "Mic", 0x0 },
2187 { "Internal Mic", 0x1 },
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002188 { "Line In", 0x2 },
Takashi Iwaid6815182006-03-23 16:06:23 +01002189 },
2190};
2191
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002192#define alc880_lg_lw_modes alc880_threestack_modes
2193
Takashi Iwaid6815182006-03-23 16:06:23 +01002194static struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002195 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2196 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2197 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2198 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
2199 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2200 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2201 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2202 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2203 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2204 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaid6815182006-03-23 16:06:23 +01002205 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2206 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2207 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
2208 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002209 {
2210 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2211 .name = "Channel Mode",
2212 .info = alc_ch_mode_info,
2213 .get = alc_ch_mode_get,
2214 .put = alc_ch_mode_put,
2215 },
Takashi Iwaid6815182006-03-23 16:06:23 +01002216 { } /* end */
2217};
2218
2219static struct hda_verb alc880_lg_lw_init_verbs[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002220 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2221 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
2222 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
2223
Takashi Iwaid6815182006-03-23 16:06:23 +01002224 /* set capture source to mic-in */
2225 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2226 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2227 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02002228 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaid6815182006-03-23 16:06:23 +01002229 /* speaker-out */
2230 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2231 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2232 /* HP-out */
Takashi Iwaid6815182006-03-23 16:06:23 +01002233 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2234 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2235 /* mic-in to input */
2236 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2237 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2238 /* built-in mic */
2239 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2240 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2241 /* jack sense */
2242 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1},
2243 { }
2244};
2245
2246/* toggle speaker-output according to the hp-jack state */
2247static void alc880_lg_lw_automute(struct hda_codec *codec)
2248{
2249 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002250 unsigned char bits;
Takashi Iwaid6815182006-03-23 16:06:23 +01002251
2252 present = snd_hda_codec_read(codec, 0x1b, 0,
2253 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002254 bits = present ? HDA_AMP_MUTE : 0;
2255 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
2256 HDA_AMP_MUTE, bits);
Takashi Iwaid6815182006-03-23 16:06:23 +01002257}
2258
2259static void alc880_lg_lw_unsol_event(struct hda_codec *codec, unsigned int res)
2260{
2261 /* Looks like the unsol event is incompatible with the standard
2262 * definition. 4bit tag is placed at 28 bit!
2263 */
2264 if ((res >> 28) == 0x01)
2265 alc880_lg_lw_automute(codec);
2266}
2267
Takashi Iwaicb53c622007-08-10 17:21:45 +02002268#ifdef CONFIG_SND_HDA_POWER_SAVE
2269static struct hda_amp_list alc880_loopbacks[] = {
2270 { 0x0b, HDA_INPUT, 0 },
2271 { 0x0b, HDA_INPUT, 1 },
2272 { 0x0b, HDA_INPUT, 2 },
2273 { 0x0b, HDA_INPUT, 3 },
2274 { 0x0b, HDA_INPUT, 4 },
2275 { } /* end */
2276};
2277
2278static struct hda_amp_list alc880_lg_loopbacks[] = {
2279 { 0x0b, HDA_INPUT, 1 },
2280 { 0x0b, HDA_INPUT, 6 },
2281 { 0x0b, HDA_INPUT, 7 },
2282 { } /* end */
2283};
2284#endif
2285
Takashi Iwaid6815182006-03-23 16:06:23 +01002286/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002287 * Common callbacks
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002288 */
Takashi Iwai16ded522005-06-10 19:58:24 +02002289
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290static int alc_init(struct hda_codec *codec)
2291{
2292 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002293 unsigned int i;
2294
2295 for (i = 0; i < spec->num_init_verbs; i++)
2296 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002297
2298 if (spec->init_hook)
2299 spec->init_hook(codec);
2300
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 return 0;
2302}
2303
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002304static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
2305{
2306 struct alc_spec *spec = codec->spec;
2307
2308 if (spec->unsol_event)
2309 spec->unsol_event(codec, res);
2310}
2311
Takashi Iwaicb53c622007-08-10 17:21:45 +02002312#ifdef CONFIG_SND_HDA_POWER_SAVE
2313static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
2314{
2315 struct alc_spec *spec = codec->spec;
2316 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
2317}
2318#endif
2319
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320/*
2321 * Analog playback callbacks
2322 */
2323static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
2324 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002325 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326{
2327 struct alc_spec *spec = codec->spec;
2328 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
2329}
2330
2331static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2332 struct hda_codec *codec,
2333 unsigned int stream_tag,
2334 unsigned int format,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002335 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336{
2337 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002338 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
2339 stream_tag, format, substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340}
2341
2342static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
2343 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002344 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345{
2346 struct alc_spec *spec = codec->spec;
2347 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
2348}
2349
2350/*
2351 * Digital out
2352 */
2353static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
2354 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002355 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356{
2357 struct alc_spec *spec = codec->spec;
2358 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
2359}
2360
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002361static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2362 struct hda_codec *codec,
2363 unsigned int stream_tag,
2364 unsigned int format,
2365 struct snd_pcm_substream *substream)
2366{
2367 struct alc_spec *spec = codec->spec;
2368 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
2369 stream_tag, format, substream);
2370}
2371
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
2373 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002374 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375{
2376 struct alc_spec *spec = codec->spec;
2377 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
2378}
2379
2380/*
2381 * Analog capture
2382 */
Takashi Iwai63300792008-01-24 15:31:36 +01002383static int alc880_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384 struct hda_codec *codec,
2385 unsigned int stream_tag,
2386 unsigned int format,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002387 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388{
2389 struct alc_spec *spec = codec->spec;
2390
Takashi Iwai63300792008-01-24 15:31:36 +01002391 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392 stream_tag, 0, format);
2393 return 0;
2394}
2395
Takashi Iwai63300792008-01-24 15:31:36 +01002396static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002398 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399{
2400 struct alc_spec *spec = codec->spec;
2401
Takashi Iwai63300792008-01-24 15:31:36 +01002402 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002403 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 return 0;
2405}
2406
2407
2408/*
2409 */
2410static struct hda_pcm_stream alc880_pcm_analog_playback = {
2411 .substreams = 1,
2412 .channels_min = 2,
2413 .channels_max = 8,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002414 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 .ops = {
2416 .open = alc880_playback_pcm_open,
2417 .prepare = alc880_playback_pcm_prepare,
2418 .cleanup = alc880_playback_pcm_cleanup
2419 },
2420};
2421
2422static struct hda_pcm_stream alc880_pcm_analog_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01002423 .substreams = 1,
2424 .channels_min = 2,
2425 .channels_max = 2,
2426 /* NID is set in alc_build_pcms */
2427};
2428
2429static struct hda_pcm_stream alc880_pcm_analog_alt_playback = {
2430 .substreams = 1,
2431 .channels_min = 2,
2432 .channels_max = 2,
2433 /* NID is set in alc_build_pcms */
2434};
2435
2436static struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
2437 .substreams = 2, /* can be overridden */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438 .channels_min = 2,
2439 .channels_max = 2,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002440 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441 .ops = {
Takashi Iwai63300792008-01-24 15:31:36 +01002442 .prepare = alc880_alt_capture_pcm_prepare,
2443 .cleanup = alc880_alt_capture_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444 },
2445};
2446
2447static struct hda_pcm_stream alc880_pcm_digital_playback = {
2448 .substreams = 1,
2449 .channels_min = 2,
2450 .channels_max = 2,
2451 /* NID is set in alc_build_pcms */
2452 .ops = {
2453 .open = alc880_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002454 .close = alc880_dig_playback_pcm_close,
2455 .prepare = alc880_dig_playback_pcm_prepare
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456 },
2457};
2458
2459static struct hda_pcm_stream alc880_pcm_digital_capture = {
2460 .substreams = 1,
2461 .channels_min = 2,
2462 .channels_max = 2,
2463 /* NID is set in alc_build_pcms */
2464};
2465
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01002466/* Used by alc_build_pcms to flag that a PCM has no playback stream */
Takashi Iwai63300792008-01-24 15:31:36 +01002467static struct hda_pcm_stream alc_pcm_null_stream = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01002468 .substreams = 0,
2469 .channels_min = 0,
2470 .channels_max = 0,
2471};
2472
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473static int alc_build_pcms(struct hda_codec *codec)
2474{
2475 struct alc_spec *spec = codec->spec;
2476 struct hda_pcm *info = spec->pcm_rec;
2477 int i;
2478
2479 codec->num_pcms = 1;
2480 codec->pcm_info = info;
2481
2482 info->name = spec->stream_name_analog;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002483 if (spec->stream_analog_playback) {
2484 snd_assert(spec->multiout.dac_nids, return -EINVAL);
2485 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
2486 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
2487 }
2488 if (spec->stream_analog_capture) {
2489 snd_assert(spec->adc_nids, return -EINVAL);
2490 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
2491 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
2492 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493
Takashi Iwai4a471b72005-12-07 13:56:29 +01002494 if (spec->channel_mode) {
2495 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
2496 for (i = 0; i < spec->num_channel_mode; i++) {
2497 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
2498 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
2499 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500 }
2501 }
2502
Takashi Iwaie08a0072006-09-07 17:52:14 +02002503 /* SPDIF for stream index #1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02002505 codec->num_pcms = 2;
Takashi Iwaic06134d2006-10-11 18:49:13 +02002506 info = spec->pcm_rec + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507 info->name = spec->stream_name_digital;
Takashi Iwai7ba72ba2008-02-06 14:03:20 +01002508 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002509 if (spec->multiout.dig_out_nid &&
2510 spec->stream_digital_playback) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
2512 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
2513 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01002514 if (spec->dig_in_nid &&
2515 spec->stream_digital_capture) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
2517 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
2518 }
2519 }
2520
Takashi Iwaie08a0072006-09-07 17:52:14 +02002521 /* If the use of more than one ADC is requested for the current
2522 * model, configure a second analog capture-only PCM.
2523 */
2524 /* Additional Analaog capture for index #2 */
Takashi Iwai63300792008-01-24 15:31:36 +01002525 if ((spec->alt_dac_nid && spec->stream_analog_alt_playback) ||
2526 (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture)) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02002527 codec->num_pcms = 3;
Takashi Iwaic06134d2006-10-11 18:49:13 +02002528 info = spec->pcm_rec + 2;
Takashi Iwaie08a0072006-09-07 17:52:14 +02002529 info->name = spec->stream_name_analog;
Takashi Iwai63300792008-01-24 15:31:36 +01002530 if (spec->alt_dac_nid) {
2531 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
2532 *spec->stream_analog_alt_playback;
2533 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
2534 spec->alt_dac_nid;
2535 } else {
2536 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
2537 alc_pcm_null_stream;
2538 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
2539 }
2540 if (spec->num_adc_nids > 1) {
2541 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
2542 *spec->stream_analog_alt_capture;
2543 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
2544 spec->adc_nids[1];
2545 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
2546 spec->num_adc_nids - 1;
2547 } else {
2548 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
2549 alc_pcm_null_stream;
2550 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
Takashi Iwaie08a0072006-09-07 17:52:14 +02002551 }
2552 }
2553
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554 return 0;
2555}
2556
2557static void alc_free(struct hda_codec *codec)
2558{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002559 struct alc_spec *spec = codec->spec;
2560 unsigned int i;
2561
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002562 if (!spec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002563 return;
2564
2565 if (spec->kctl_alloc) {
2566 for (i = 0; i < spec->num_kctl_used; i++)
2567 kfree(spec->kctl_alloc[i].name);
2568 kfree(spec->kctl_alloc);
2569 }
2570 kfree(spec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571}
2572
2573/*
2574 */
2575static struct hda_codec_ops alc_patch_ops = {
2576 .build_controls = alc_build_controls,
2577 .build_pcms = alc_build_pcms,
2578 .init = alc_init,
2579 .free = alc_free,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002580 .unsol_event = alc_unsol_event,
Takashi Iwaicb53c622007-08-10 17:21:45 +02002581#ifdef CONFIG_SND_HDA_POWER_SAVE
2582 .check_power_status = alc_check_power_status,
2583#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584};
2585
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002586
2587/*
2588 * Test configuration for debugging
2589 *
2590 * Almost all inputs/outputs are enabled. I/O pins can be configured via
2591 * enum controls.
2592 */
2593#ifdef CONFIG_SND_DEBUG
2594static hda_nid_t alc880_test_dac_nids[4] = {
2595 0x02, 0x03, 0x04, 0x05
2596};
2597
2598static struct hda_input_mux alc880_test_capture_source = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002599 .num_items = 7,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002600 .items = {
2601 { "In-1", 0x0 },
2602 { "In-2", 0x1 },
2603 { "In-3", 0x2 },
2604 { "In-4", 0x3 },
2605 { "CD", 0x4 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002606 { "Front", 0x5 },
2607 { "Surround", 0x6 },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002608 },
2609};
2610
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002611static struct hda_channel_mode alc880_test_modes[4] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002612 { 2, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02002613 { 4, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002614 { 6, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02002615 { 8, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002616};
2617
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002618static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
2619 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002620{
2621 static char *texts[] = {
2622 "N/A", "Line Out", "HP Out",
2623 "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
2624 };
2625 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2626 uinfo->count = 1;
2627 uinfo->value.enumerated.items = 8;
2628 if (uinfo->value.enumerated.item >= 8)
2629 uinfo->value.enumerated.item = 7;
2630 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
2631 return 0;
2632}
2633
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002634static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol,
2635 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002636{
2637 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2638 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
2639 unsigned int pin_ctl, item = 0;
2640
2641 pin_ctl = snd_hda_codec_read(codec, nid, 0,
2642 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
2643 if (pin_ctl & AC_PINCTL_OUT_EN) {
2644 if (pin_ctl & AC_PINCTL_HP_EN)
2645 item = 2;
2646 else
2647 item = 1;
2648 } else if (pin_ctl & AC_PINCTL_IN_EN) {
2649 switch (pin_ctl & AC_PINCTL_VREFEN) {
2650 case AC_PINCTL_VREF_HIZ: item = 3; break;
2651 case AC_PINCTL_VREF_50: item = 4; break;
2652 case AC_PINCTL_VREF_GRD: item = 5; break;
2653 case AC_PINCTL_VREF_80: item = 6; break;
2654 case AC_PINCTL_VREF_100: item = 7; break;
2655 }
2656 }
2657 ucontrol->value.enumerated.item[0] = item;
2658 return 0;
2659}
2660
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002661static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
2662 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002663{
2664 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2665 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
2666 static unsigned int ctls[] = {
2667 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
2668 AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
2669 AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
2670 AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
2671 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
2672 AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
2673 };
2674 unsigned int old_ctl, new_ctl;
2675
2676 old_ctl = snd_hda_codec_read(codec, nid, 0,
2677 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
2678 new_ctl = ctls[ucontrol->value.enumerated.item[0]];
2679 if (old_ctl != new_ctl) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002680 int val;
2681 snd_hda_codec_write_cache(codec, nid, 0,
2682 AC_VERB_SET_PIN_WIDGET_CONTROL,
2683 new_ctl);
Takashi Iwai47fd8302007-08-10 17:11:07 +02002684 val = ucontrol->value.enumerated.item[0] >= 3 ?
2685 HDA_AMP_MUTE : 0;
2686 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
2687 HDA_AMP_MUTE, val);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002688 return 1;
2689 }
2690 return 0;
2691}
2692
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002693static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
2694 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002695{
2696 static char *texts[] = {
2697 "Front", "Surround", "CLFE", "Side"
2698 };
2699 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2700 uinfo->count = 1;
2701 uinfo->value.enumerated.items = 4;
2702 if (uinfo->value.enumerated.item >= 4)
2703 uinfo->value.enumerated.item = 3;
2704 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
2705 return 0;
2706}
2707
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002708static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol,
2709 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002710{
2711 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2712 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
2713 unsigned int sel;
2714
2715 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
2716 ucontrol->value.enumerated.item[0] = sel & 3;
2717 return 0;
2718}
2719
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002720static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
2721 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002722{
2723 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2724 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
2725 unsigned int sel;
2726
2727 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
2728 if (ucontrol->value.enumerated.item[0] != sel) {
2729 sel = ucontrol->value.enumerated.item[0] & 3;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002730 snd_hda_codec_write_cache(codec, nid, 0,
2731 AC_VERB_SET_CONNECT_SEL, sel);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002732 return 1;
2733 }
2734 return 0;
2735}
2736
2737#define PIN_CTL_TEST(xname,nid) { \
2738 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2739 .name = xname, \
2740 .info = alc_test_pin_ctl_info, \
2741 .get = alc_test_pin_ctl_get, \
2742 .put = alc_test_pin_ctl_put, \
2743 .private_value = nid \
2744 }
2745
2746#define PIN_SRC_TEST(xname,nid) { \
2747 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2748 .name = xname, \
2749 .info = alc_test_pin_src_info, \
2750 .get = alc_test_pin_src_get, \
2751 .put = alc_test_pin_src_put, \
2752 .private_value = nid \
2753 }
2754
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002755static struct snd_kcontrol_new alc880_test_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02002756 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2757 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2758 HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
2759 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002760 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2761 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
2762 HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
2763 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002764 PIN_CTL_TEST("Front Pin Mode", 0x14),
2765 PIN_CTL_TEST("Surround Pin Mode", 0x15),
2766 PIN_CTL_TEST("CLFE Pin Mode", 0x16),
2767 PIN_CTL_TEST("Side Pin Mode", 0x17),
2768 PIN_CTL_TEST("In-1 Pin Mode", 0x18),
2769 PIN_CTL_TEST("In-2 Pin Mode", 0x19),
2770 PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
2771 PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
2772 PIN_SRC_TEST("In-1 Pin Source", 0x18),
2773 PIN_SRC_TEST("In-2 Pin Source", 0x19),
2774 PIN_SRC_TEST("In-3 Pin Source", 0x1a),
2775 PIN_SRC_TEST("In-4 Pin Source", 0x1b),
2776 HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
2777 HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
2778 HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
2779 HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
2780 HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
2781 HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
2782 HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
2783 HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
2784 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
2785 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002786 {
2787 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2788 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002789 .info = alc_ch_mode_info,
2790 .get = alc_ch_mode_get,
2791 .put = alc_ch_mode_put,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002792 },
2793 { } /* end */
2794};
2795
2796static struct hda_verb alc880_test_init_verbs[] = {
2797 /* Unmute inputs of 0x0c - 0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02002798 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2799 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2800 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2801 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2802 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2803 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2804 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2805 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002806 /* Vol output for 0x0c-0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02002807 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2808 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2809 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2810 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002811 /* Set output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02002812 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2813 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2814 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2815 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002816 /* Unmute output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02002817 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2818 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2819 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2820 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002821 /* Set input pins 0x18-0x1c */
Takashi Iwai16ded522005-06-10 19:58:24 +02002822 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2823 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai05acb862005-06-10 19:50:25 +02002824 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2825 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2826 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002827 /* Mute input pins 0x18-0x1b */
Takashi Iwai05acb862005-06-10 19:50:25 +02002828 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2829 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2830 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2831 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002832 /* ADC set up */
Takashi Iwai05acb862005-06-10 19:50:25 +02002833 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002834 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02002835 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002836 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02002837 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002838 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02002839 /* Analog input/passthru */
2840 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2841 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2842 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2843 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2844 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002845 { }
2846};
2847#endif
2848
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849/*
2850 */
2851
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002852static const char *alc880_models[ALC880_MODEL_LAST] = {
2853 [ALC880_3ST] = "3stack",
2854 [ALC880_TCL_S700] = "tcl",
2855 [ALC880_3ST_DIG] = "3stack-digout",
2856 [ALC880_CLEVO] = "clevo",
2857 [ALC880_5ST] = "5stack",
2858 [ALC880_5ST_DIG] = "5stack-digout",
2859 [ALC880_W810] = "w810",
2860 [ALC880_Z71V] = "z71v",
2861 [ALC880_6ST] = "6stack",
2862 [ALC880_6ST_DIG] = "6stack-digout",
2863 [ALC880_ASUS] = "asus",
2864 [ALC880_ASUS_W1V] = "asus-w1v",
2865 [ALC880_ASUS_DIG] = "asus-dig",
2866 [ALC880_ASUS_DIG2] = "asus-dig2",
2867 [ALC880_UNIWILL_DIG] = "uniwill",
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01002868 [ALC880_UNIWILL_P53] = "uniwill-p53",
2869 [ALC880_FUJITSU] = "fujitsu",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002870 [ALC880_F1734] = "F1734",
2871 [ALC880_LG] = "lg",
2872 [ALC880_LG_LW] = "lg-lw",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002873#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002874 [ALC880_TEST] = "test",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002875#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002876 [ALC880_AUTO] = "auto",
2877};
2878
2879static struct snd_pci_quirk alc880_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002880 SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002881 SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
2882 SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
2883 SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
2884 SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
2885 SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
2886 SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
2887 SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
2888 SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002889 SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
2890 SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002891 SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
2892 SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
2893 SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
2894 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
2895 SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
2896 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
2897 SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
2898 /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
2899 SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
2900 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
Tobin Davis0e4ceb72007-01-08 10:54:26 +01002901 SND_PCI_QUIRK(0x1043, 0x814e, "ASUS", ALC880_ASUS),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002902 SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
2903 SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
2904 SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002905 SND_PCI_QUIRK(0x1043, 0, "ASUS", ALC880_ASUS), /* default ASUS */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002906 SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002907 SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
2908 SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002909 SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
2910 SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002911 SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
2912 SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
2913 SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
2914 SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002915 SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
2916 SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002917 SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002918 SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002919 SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002920 SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002921 SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
2922 SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002923 SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
2924 SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002925 SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002926 SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002927 SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01002928 SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002929 SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002930 SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
2931 SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002932 SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002933 SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
2934 SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
2935 SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
2936 SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002937 SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
2938 SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002939 SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002940 SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002941 SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
2942 SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002943 SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
2944 SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
2945 SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002946 SND_PCI_QUIRK(0x8086, 0, "Intel mobo", ALC880_3ST), /* default Intel */
2947 SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
2948 SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949 {}
2950};
2951
Takashi Iwai16ded522005-06-10 19:58:24 +02002952/*
Kailang Yangdf694da2005-12-05 19:42:22 +01002953 * ALC880 codec presets
Takashi Iwai16ded522005-06-10 19:58:24 +02002954 */
Takashi Iwai16ded522005-06-10 19:58:24 +02002955static struct alc_config_preset alc880_presets[] = {
2956 [ALC880_3ST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002957 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002958 .init_verbs = { alc880_volume_init_verbs,
2959 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02002960 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02002961 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02002962 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
2963 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02002964 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02002965 .input_mux = &alc880_capture_source,
2966 },
2967 [ALC880_3ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002968 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002969 .init_verbs = { alc880_volume_init_verbs,
2970 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02002971 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02002972 .dac_nids = alc880_dac_nids,
2973 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02002974 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
2975 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02002976 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02002977 .input_mux = &alc880_capture_source,
2978 },
Kailang Yangdf694da2005-12-05 19:42:22 +01002979 [ALC880_TCL_S700] = {
2980 .mixers = { alc880_tcl_s700_mixer },
2981 .init_verbs = { alc880_volume_init_verbs,
2982 alc880_pin_tcl_S700_init_verbs,
2983 alc880_gpio2_init_verbs },
2984 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
2985 .dac_nids = alc880_dac_nids,
2986 .hp_nid = 0x03,
2987 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
2988 .channel_mode = alc880_2_jack_modes,
2989 .input_mux = &alc880_capture_source,
2990 },
Takashi Iwai16ded522005-06-10 19:58:24 +02002991 [ALC880_5ST] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002992 .mixers = { alc880_three_stack_mixer,
2993 alc880_five_stack_mixer},
2994 .init_verbs = { alc880_volume_init_verbs,
2995 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02002996 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
2997 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02002998 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
2999 .channel_mode = alc880_fivestack_modes,
3000 .input_mux = &alc880_capture_source,
3001 },
3002 [ALC880_5ST_DIG] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003003 .mixers = { alc880_three_stack_mixer,
3004 alc880_five_stack_mixer },
3005 .init_verbs = { alc880_volume_init_verbs,
3006 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003007 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3008 .dac_nids = alc880_dac_nids,
3009 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003010 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
3011 .channel_mode = alc880_fivestack_modes,
3012 .input_mux = &alc880_capture_source,
3013 },
Takashi Iwaib6482d42005-06-27 15:32:43 +02003014 [ALC880_6ST] = {
3015 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003016 .init_verbs = { alc880_volume_init_verbs,
3017 alc880_pin_6stack_init_verbs },
Takashi Iwaib6482d42005-06-27 15:32:43 +02003018 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
3019 .dac_nids = alc880_6st_dac_nids,
3020 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
3021 .channel_mode = alc880_sixstack_modes,
3022 .input_mux = &alc880_6stack_capture_source,
3023 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003024 [ALC880_6ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003025 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003026 .init_verbs = { alc880_volume_init_verbs,
3027 alc880_pin_6stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003028 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
3029 .dac_nids = alc880_6st_dac_nids,
3030 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003031 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
3032 .channel_mode = alc880_sixstack_modes,
3033 .input_mux = &alc880_6stack_capture_source,
3034 },
3035 [ALC880_W810] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003036 .mixers = { alc880_w810_base_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003037 .init_verbs = { alc880_volume_init_verbs,
3038 alc880_pin_w810_init_verbs,
Takashi Iwaib0af0de2005-06-21 14:49:19 +02003039 alc880_gpio2_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003040 .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
3041 .dac_nids = alc880_w810_dac_nids,
3042 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003043 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
3044 .channel_mode = alc880_w810_modes,
3045 .input_mux = &alc880_capture_source,
3046 },
3047 [ALC880_Z71V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003048 .mixers = { alc880_z71v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003049 .init_verbs = { alc880_volume_init_verbs,
3050 alc880_pin_z71v_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003051 .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
3052 .dac_nids = alc880_z71v_dac_nids,
3053 .dig_out_nid = ALC880_DIGOUT_NID,
3054 .hp_nid = 0x03,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003055 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3056 .channel_mode = alc880_2_jack_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02003057 .input_mux = &alc880_capture_source,
3058 },
3059 [ALC880_F1734] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003060 .mixers = { alc880_f1734_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003061 .init_verbs = { alc880_volume_init_verbs,
3062 alc880_pin_f1734_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003063 .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
3064 .dac_nids = alc880_f1734_dac_nids,
3065 .hp_nid = 0x02,
3066 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3067 .channel_mode = alc880_2_jack_modes,
Takashi Iwai937b4162008-02-11 14:52:36 +01003068 .input_mux = &alc880_f1734_capture_source,
3069 .unsol_event = alc880_uniwill_p53_unsol_event,
3070 .init_hook = alc880_uniwill_p53_hp_automute,
Takashi Iwai16ded522005-06-10 19:58:24 +02003071 },
3072 [ALC880_ASUS] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003073 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003074 .init_verbs = { alc880_volume_init_verbs,
3075 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003076 alc880_gpio1_init_verbs },
3077 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3078 .dac_nids = alc880_asus_dac_nids,
3079 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3080 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003081 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003082 .input_mux = &alc880_capture_source,
3083 },
3084 [ALC880_ASUS_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003085 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003086 .init_verbs = { alc880_volume_init_verbs,
3087 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003088 alc880_gpio1_init_verbs },
3089 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3090 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003091 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003092 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3093 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003094 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003095 .input_mux = &alc880_capture_source,
3096 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003097 [ALC880_ASUS_DIG2] = {
3098 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003099 .init_verbs = { alc880_volume_init_verbs,
3100 alc880_pin_asus_init_verbs,
Kailang Yangdf694da2005-12-05 19:42:22 +01003101 alc880_gpio2_init_verbs }, /* use GPIO2 */
3102 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3103 .dac_nids = alc880_asus_dac_nids,
3104 .dig_out_nid = ALC880_DIGOUT_NID,
3105 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3106 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003107 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01003108 .input_mux = &alc880_capture_source,
3109 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003110 [ALC880_ASUS_W1V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003111 .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003112 .init_verbs = { alc880_volume_init_verbs,
3113 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003114 alc880_gpio1_init_verbs },
3115 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3116 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003117 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003118 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3119 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003120 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003121 .input_mux = &alc880_capture_source,
3122 },
3123 [ALC880_UNIWILL_DIG] = {
Takashi Iwai3c10a9d2005-08-23 20:02:27 +02003124 .mixers = { alc880_asus_mixer, alc880_pcbeep_mixer },
Kailang Yangccc656c2006-10-17 12:32:26 +02003125 .init_verbs = { alc880_volume_init_verbs,
3126 alc880_pin_asus_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003127 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3128 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003129 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003130 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3131 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003132 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003133 .input_mux = &alc880_capture_source,
3134 },
Kailang Yangccc656c2006-10-17 12:32:26 +02003135 [ALC880_UNIWILL] = {
3136 .mixers = { alc880_uniwill_mixer },
3137 .init_verbs = { alc880_volume_init_verbs,
3138 alc880_uniwill_init_verbs },
3139 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3140 .dac_nids = alc880_asus_dac_nids,
3141 .dig_out_nid = ALC880_DIGOUT_NID,
3142 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3143 .channel_mode = alc880_threestack_modes,
3144 .need_dac_fix = 1,
3145 .input_mux = &alc880_capture_source,
3146 .unsol_event = alc880_uniwill_unsol_event,
3147 .init_hook = alc880_uniwill_automute,
3148 },
3149 [ALC880_UNIWILL_P53] = {
3150 .mixers = { alc880_uniwill_p53_mixer },
3151 .init_verbs = { alc880_volume_init_verbs,
3152 alc880_uniwill_p53_init_verbs },
3153 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3154 .dac_nids = alc880_asus_dac_nids,
3155 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003156 .channel_mode = alc880_threestack_modes,
3157 .input_mux = &alc880_capture_source,
3158 .unsol_event = alc880_uniwill_p53_unsol_event,
3159 .init_hook = alc880_uniwill_p53_hp_automute,
3160 },
3161 [ALC880_FUJITSU] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003162 .mixers = { alc880_fujitsu_mixer,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003163 alc880_pcbeep_mixer, },
3164 .init_verbs = { alc880_volume_init_verbs,
3165 alc880_uniwill_p53_init_verbs,
3166 alc880_beep_init_verbs },
3167 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3168 .dac_nids = alc880_dac_nids,
Takashi Iwaid53d7d92007-08-20 15:20:02 +02003169 .dig_out_nid = ALC880_DIGOUT_NID,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003170 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3171 .channel_mode = alc880_2_jack_modes,
Kailang Yangccc656c2006-10-17 12:32:26 +02003172 .input_mux = &alc880_capture_source,
3173 .unsol_event = alc880_uniwill_p53_unsol_event,
3174 .init_hook = alc880_uniwill_p53_hp_automute,
3175 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003176 [ALC880_CLEVO] = {
3177 .mixers = { alc880_three_stack_mixer },
3178 .init_verbs = { alc880_volume_init_verbs,
3179 alc880_pin_clevo_init_verbs },
3180 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3181 .dac_nids = alc880_dac_nids,
3182 .hp_nid = 0x03,
3183 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3184 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003185 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01003186 .input_mux = &alc880_capture_source,
3187 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003188 [ALC880_LG] = {
3189 .mixers = { alc880_lg_mixer },
3190 .init_verbs = { alc880_volume_init_verbs,
3191 alc880_lg_init_verbs },
3192 .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids),
3193 .dac_nids = alc880_lg_dac_nids,
3194 .dig_out_nid = ALC880_DIGOUT_NID,
3195 .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
3196 .channel_mode = alc880_lg_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003197 .need_dac_fix = 1,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003198 .input_mux = &alc880_lg_capture_source,
3199 .unsol_event = alc880_lg_unsol_event,
3200 .init_hook = alc880_lg_automute,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003201#ifdef CONFIG_SND_HDA_POWER_SAVE
3202 .loopbacks = alc880_lg_loopbacks,
3203#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003204 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003205 [ALC880_LG_LW] = {
3206 .mixers = { alc880_lg_lw_mixer },
3207 .init_verbs = { alc880_volume_init_verbs,
3208 alc880_lg_lw_init_verbs },
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003209 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwaid6815182006-03-23 16:06:23 +01003210 .dac_nids = alc880_dac_nids,
3211 .dig_out_nid = ALC880_DIGOUT_NID,
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003212 .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
3213 .channel_mode = alc880_lg_lw_modes,
Takashi Iwaid6815182006-03-23 16:06:23 +01003214 .input_mux = &alc880_lg_lw_capture_source,
3215 .unsol_event = alc880_lg_lw_unsol_event,
3216 .init_hook = alc880_lg_lw_automute,
3217 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003218#ifdef CONFIG_SND_DEBUG
3219 [ALC880_TEST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003220 .mixers = { alc880_test_mixer },
3221 .init_verbs = { alc880_test_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003222 .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
3223 .dac_nids = alc880_test_dac_nids,
3224 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003225 .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
3226 .channel_mode = alc880_test_modes,
3227 .input_mux = &alc880_test_capture_source,
3228 },
3229#endif
3230};
3231
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003232/*
3233 * Automatic parse of I/O pins from the BIOS configuration
3234 */
3235
3236#define NUM_CONTROL_ALLOC 32
3237#define NUM_VERB_ALLOC 32
3238
3239enum {
3240 ALC_CTL_WIDGET_VOL,
3241 ALC_CTL_WIDGET_MUTE,
3242 ALC_CTL_BIND_MUTE,
3243};
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003244static struct snd_kcontrol_new alc880_control_templates[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003245 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
3246 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Takashi Iwai985be542005-11-02 18:26:49 +01003247 HDA_BIND_MUTE(NULL, 0, 0, 0),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003248};
3249
3250/* add dynamic controls */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003251static int add_control(struct alc_spec *spec, int type, const char *name,
3252 unsigned long val)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003253{
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003254 struct snd_kcontrol_new *knew;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003255
3256 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
3257 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
3258
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003259 /* array + terminator */
3260 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL);
3261 if (!knew)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003262 return -ENOMEM;
3263 if (spec->kctl_alloc) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003264 memcpy(knew, spec->kctl_alloc,
3265 sizeof(*knew) * spec->num_kctl_alloc);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003266 kfree(spec->kctl_alloc);
3267 }
3268 spec->kctl_alloc = knew;
3269 spec->num_kctl_alloc = num;
3270 }
3271
3272 knew = &spec->kctl_alloc[spec->num_kctl_used];
3273 *knew = alc880_control_templates[type];
Paulo Marques543537b2005-06-23 00:09:02 -07003274 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003275 if (!knew->name)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003276 return -ENOMEM;
3277 knew->private_value = val;
3278 spec->num_kctl_used++;
3279 return 0;
3280}
3281
3282#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
3283#define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
3284#define alc880_is_multi_pin(nid) ((nid) >= 0x18)
3285#define alc880_multi_pin_idx(nid) ((nid) - 0x18)
3286#define alc880_is_input_pin(nid) ((nid) >= 0x18)
3287#define alc880_input_pin_idx(nid) ((nid) - 0x18)
3288#define alc880_idx_to_dac(nid) ((nid) + 0x02)
3289#define alc880_dac_to_idx(nid) ((nid) - 0x02)
3290#define alc880_idx_to_mixer(nid) ((nid) + 0x0c)
3291#define alc880_idx_to_selector(nid) ((nid) + 0x10)
3292#define ALC880_PIN_CD_NID 0x1c
3293
3294/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003295static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
3296 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003297{
3298 hda_nid_t nid;
3299 int assigned[4];
3300 int i, j;
3301
3302 memset(assigned, 0, sizeof(assigned));
Takashi Iwaib0af0de2005-06-21 14:49:19 +02003303 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003304
3305 /* check the pins hardwired to audio widget */
3306 for (i = 0; i < cfg->line_outs; i++) {
3307 nid = cfg->line_out_pins[i];
3308 if (alc880_is_fixed_pin(nid)) {
3309 int idx = alc880_fixed_pin_idx(nid);
Libin Yang5014f192005-11-23 15:48:36 +01003310 spec->multiout.dac_nids[i] = alc880_idx_to_dac(idx);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003311 assigned[idx] = 1;
3312 }
3313 }
3314 /* left pins can be connect to any audio widget */
3315 for (i = 0; i < cfg->line_outs; i++) {
3316 nid = cfg->line_out_pins[i];
3317 if (alc880_is_fixed_pin(nid))
3318 continue;
3319 /* search for an empty channel */
3320 for (j = 0; j < cfg->line_outs; j++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003321 if (!assigned[j]) {
3322 spec->multiout.dac_nids[i] =
3323 alc880_idx_to_dac(j);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003324 assigned[j] = 1;
3325 break;
3326 }
3327 }
3328 }
3329 spec->multiout.num_dacs = cfg->line_outs;
3330 return 0;
3331}
3332
3333/* add playback controls from the parsed DAC table */
Kailang Yangdf694da2005-12-05 19:42:22 +01003334static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
3335 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003336{
3337 char name[32];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003338 static const char *chname[4] = {
3339 "Front", "Surround", NULL /*CLFE*/, "Side"
3340 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003341 hda_nid_t nid;
3342 int i, err;
3343
3344 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003345 if (!spec->multiout.dac_nids[i])
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003346 continue;
3347 nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
3348 if (i == 2) {
3349 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003350 err = add_control(spec, ALC_CTL_WIDGET_VOL,
3351 "Center Playback Volume",
3352 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
3353 HDA_OUTPUT));
3354 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003355 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003356 err = add_control(spec, ALC_CTL_WIDGET_VOL,
3357 "LFE Playback Volume",
3358 HDA_COMPOSE_AMP_VAL(nid, 2, 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_BIND_MUTE,
3363 "Center Playback Switch",
3364 HDA_COMPOSE_AMP_VAL(nid, 1, 2,
3365 HDA_INPUT));
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 "LFE Playback Switch",
3370 HDA_COMPOSE_AMP_VAL(nid, 2, 2,
3371 HDA_INPUT));
3372 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003373 return err;
3374 } else {
3375 sprintf(name, "%s Playback Volume", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003376 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
3377 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
3378 HDA_OUTPUT));
3379 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003380 return err;
3381 sprintf(name, "%s Playback Switch", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003382 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
3383 HDA_COMPOSE_AMP_VAL(nid, 3, 2,
3384 HDA_INPUT));
3385 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003386 return err;
3387 }
3388 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003389 return 0;
3390}
3391
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003392/* add playback controls for speaker and HP outputs */
3393static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
3394 const char *pfx)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003395{
3396 hda_nid_t nid;
3397 int err;
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003398 char name[32];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003399
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003400 if (!pin)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003401 return 0;
3402
3403 if (alc880_is_fixed_pin(pin)) {
3404 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
Takashi Iwai82bc9552006-03-21 11:24:42 +01003405 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003406 if (!spec->multiout.hp_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003407 spec->multiout.hp_nid = nid;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003408 else
3409 spec->multiout.extra_out_nid[0] = nid;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003410 /* control HP volume/switch on the output mixer amp */
3411 nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003412 sprintf(name, "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003413 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
3414 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
3415 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003416 return err;
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003417 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003418 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
3419 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
3420 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003421 return err;
3422 } else if (alc880_is_multi_pin(pin)) {
3423 /* set manual connection */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003424 /* we have only a switch on HP-out PIN */
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003425 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003426 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
3427 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
3428 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003429 return err;
3430 }
3431 return 0;
3432}
3433
3434/* create input playback/capture controls for the given pin */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003435static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
3436 const char *ctlname,
Kailang Yangdf694da2005-12-05 19:42:22 +01003437 int idx, hda_nid_t mix_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003438{
3439 char name[32];
Kailang Yangdf694da2005-12-05 19:42:22 +01003440 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003441
3442 sprintf(name, "%s Playback Volume", ctlname);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003443 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
3444 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
3445 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003446 return err;
3447 sprintf(name, "%s Playback Switch", ctlname);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003448 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
3449 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
3450 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003451 return err;
3452 return 0;
3453}
3454
3455/* create playback/capture controls for input pins */
Kailang Yangdf694da2005-12-05 19:42:22 +01003456static int alc880_auto_create_analog_input_ctls(struct alc_spec *spec,
3457 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003458{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003459 struct hda_input_mux *imux = &spec->private_imux;
Kailang Yangdf694da2005-12-05 19:42:22 +01003460 int i, err, idx;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003461
3462 for (i = 0; i < AUTO_PIN_LAST; i++) {
3463 if (alc880_is_input_pin(cfg->input_pins[i])) {
Kailang Yangdf694da2005-12-05 19:42:22 +01003464 idx = alc880_input_pin_idx(cfg->input_pins[i]);
Takashi Iwai4a471b72005-12-07 13:56:29 +01003465 err = new_analog_input(spec, cfg->input_pins[i],
3466 auto_pin_cfg_labels[i],
Kailang Yangdf694da2005-12-05 19:42:22 +01003467 idx, 0x0b);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003468 if (err < 0)
3469 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003470 imux->items[imux->num_items].label =
3471 auto_pin_cfg_labels[i];
3472 imux->items[imux->num_items].index =
3473 alc880_input_pin_idx(cfg->input_pins[i]);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003474 imux->num_items++;
3475 }
3476 }
3477 return 0;
3478}
3479
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003480static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
3481 unsigned int pin_type)
3482{
3483 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
3484 pin_type);
3485 /* unmute pin */
3486 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, 0xff, 0x00);
3487}
3488
Kailang Yangdf694da2005-12-05 19:42:22 +01003489static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
3490 hda_nid_t nid, int pin_type,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003491 int dac_idx)
3492{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003493 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003494 /* need the manual connection? */
3495 if (alc880_is_multi_pin(nid)) {
3496 struct alc_spec *spec = codec->spec;
3497 int idx = alc880_multi_pin_idx(nid);
3498 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
3499 AC_VERB_SET_CONNECT_SEL,
3500 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
3501 }
3502}
3503
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02003504static int get_pin_type(int line_out_type)
3505{
3506 if (line_out_type == AUTO_PIN_HP_OUT)
3507 return PIN_HP;
3508 else
3509 return PIN_OUT;
3510}
3511
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003512static void alc880_auto_init_multi_out(struct hda_codec *codec)
3513{
3514 struct alc_spec *spec = codec->spec;
3515 int i;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003516
3517 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003518 for (i = 0; i < spec->autocfg.line_outs; i++) {
3519 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02003520 int pin_type = get_pin_type(spec->autocfg.line_out_type);
3521 alc880_auto_set_output_and_unmute(codec, nid, pin_type, i);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003522 }
3523}
3524
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003525static void alc880_auto_init_extra_out(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003526{
3527 struct alc_spec *spec = codec->spec;
3528 hda_nid_t pin;
3529
Takashi Iwai82bc9552006-03-21 11:24:42 +01003530 pin = spec->autocfg.speaker_pins[0];
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003531 if (pin) /* connect to front */
3532 alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003533 pin = spec->autocfg.hp_pins[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003534 if (pin) /* connect to front */
3535 alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
3536}
3537
3538static void alc880_auto_init_analog_input(struct hda_codec *codec)
3539{
3540 struct alc_spec *spec = codec->spec;
3541 int i;
3542
3543 for (i = 0; i < AUTO_PIN_LAST; i++) {
3544 hda_nid_t nid = spec->autocfg.input_pins[i];
3545 if (alc880_is_input_pin(nid)) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003546 snd_hda_codec_write(codec, nid, 0,
3547 AC_VERB_SET_PIN_WIDGET_CONTROL,
3548 i <= AUTO_PIN_FRONT_MIC ?
3549 PIN_VREF80 : PIN_IN);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003550 if (nid != ALC880_PIN_CD_NID)
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003551 snd_hda_codec_write(codec, nid, 0,
3552 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003553 AMP_OUT_MUTE);
3554 }
3555 }
3556}
3557
3558/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003559/* return 1 if successful, 0 if the proper config is not found,
3560 * or a negative error code
3561 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003562static int alc880_parse_auto_config(struct hda_codec *codec)
3563{
3564 struct alc_spec *spec = codec->spec;
3565 int err;
Kailang Yangdf694da2005-12-05 19:42:22 +01003566 static hda_nid_t alc880_ignore[] = { 0x1d, 0 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003567
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003568 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
3569 alc880_ignore);
3570 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003571 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003572 if (!spec->autocfg.line_outs)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003573 return 0; /* can't find valid BIOS pin config */
Kailang Yangdf694da2005-12-05 19:42:22 +01003574
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003575 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
3576 if (err < 0)
3577 return err;
3578 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
3579 if (err < 0)
3580 return err;
3581 err = alc880_auto_create_extra_out(spec,
3582 spec->autocfg.speaker_pins[0],
3583 "Speaker");
3584 if (err < 0)
3585 return err;
3586 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
3587 "Headphone");
3588 if (err < 0)
3589 return err;
3590 err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg);
3591 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003592 return err;
3593
3594 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
3595
3596 if (spec->autocfg.dig_out_pin)
3597 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
3598 if (spec->autocfg.dig_in_pin)
3599 spec->dig_in_nid = ALC880_DIGIN_NID;
3600
3601 if (spec->kctl_alloc)
3602 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
3603
3604 spec->init_verbs[spec->num_init_verbs++] = alc880_volume_init_verbs;
3605
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003606 spec->num_mux_defs = 1;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003607 spec->input_mux = &spec->private_imux;
3608
3609 return 1;
3610}
3611
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003612/* additional initialization for auto-configuration model */
3613static void alc880_auto_init(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003614{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003615 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003616 alc880_auto_init_multi_out(codec);
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003617 alc880_auto_init_extra_out(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003618 alc880_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003619 if (spec->unsol_event)
3620 alc_sku_automute(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003621}
3622
3623/*
3624 * OK, here we have finally the patch for ALC880
3625 */
3626
Linus Torvalds1da177e2005-04-16 15:20:36 -07003627static int patch_alc880(struct hda_codec *codec)
3628{
3629 struct alc_spec *spec;
3630 int board_config;
Kailang Yangdf694da2005-12-05 19:42:22 +01003631 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003632
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003633 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003634 if (spec == NULL)
3635 return -ENOMEM;
3636
3637 codec->spec = spec;
3638
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003639 board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
3640 alc880_models,
3641 alc880_cfg_tbl);
3642 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003643 printk(KERN_INFO "hda_codec: Unknown model for ALC880, "
3644 "trying auto-probe from BIOS...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003645 board_config = ALC880_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003646 }
3647
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003648 if (board_config == ALC880_AUTO) {
3649 /* automatic parse from the BIOS config */
3650 err = alc880_parse_auto_config(codec);
3651 if (err < 0) {
3652 alc_free(codec);
3653 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003654 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003655 printk(KERN_INFO
3656 "hda_codec: Cannot set up configuration "
3657 "from BIOS. Using 3-stack mode...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003658 board_config = ALC880_3ST;
3659 }
3660 }
3661
Kailang Yangdf694da2005-12-05 19:42:22 +01003662 if (board_config != ALC880_AUTO)
3663 setup_preset(spec, &alc880_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664
3665 spec->stream_name_analog = "ALC880 Analog";
3666 spec->stream_analog_playback = &alc880_pcm_analog_playback;
3667 spec->stream_analog_capture = &alc880_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01003668 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669
3670 spec->stream_name_digital = "ALC880 Digital";
3671 spec->stream_digital_playback = &alc880_pcm_digital_playback;
3672 spec->stream_digital_capture = &alc880_pcm_digital_capture;
3673
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003674 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003675 /* check whether NID 0x07 is valid */
Takashi Iwai54d17402005-11-21 16:33:22 +01003676 unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003677 /* get type */
3678 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003679 if (wcap != AC_WID_AUD_IN) {
3680 spec->adc_nids = alc880_adc_nids_alt;
3681 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003682 spec->mixers[spec->num_mixers] =
3683 alc880_capture_alt_mixer;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003684 spec->num_mixers++;
3685 } else {
3686 spec->adc_nids = alc880_adc_nids;
3687 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
3688 spec->mixers[spec->num_mixers] = alc880_capture_mixer;
3689 spec->num_mixers++;
3690 }
3691 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692
Takashi Iwai2134ea42008-01-10 16:53:55 +01003693 spec->vmaster_nid = 0x0c;
3694
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695 codec->patch_ops = alc_patch_ops;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003696 if (board_config == ALC880_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003697 spec->init_hook = alc880_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02003698#ifdef CONFIG_SND_HDA_POWER_SAVE
3699 if (!spec->loopback.amplist)
3700 spec->loopback.amplist = alc880_loopbacks;
3701#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07003702
3703 return 0;
3704}
3705
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003706
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707/*
3708 * ALC260 support
3709 */
3710
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003711static hda_nid_t alc260_dac_nids[1] = {
3712 /* front */
3713 0x02,
3714};
3715
3716static hda_nid_t alc260_adc_nids[1] = {
3717 /* ADC0 */
3718 0x04,
3719};
3720
Kailang Yangdf694da2005-12-05 19:42:22 +01003721static hda_nid_t alc260_adc_nids_alt[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003722 /* ADC1 */
3723 0x05,
3724};
3725
Kailang Yangdf694da2005-12-05 19:42:22 +01003726static hda_nid_t alc260_hp_adc_nids[2] = {
3727 /* ADC1, 0 */
3728 0x05, 0x04
3729};
3730
Jonathan Woithed57fdac2006-02-28 11:38:35 +01003731/* NIDs used when simultaneous access to both ADCs makes sense. Note that
3732 * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
3733 */
3734static hda_nid_t alc260_dual_adc_nids[2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003735 /* ADC0, ADC1 */
3736 0x04, 0x05
3737};
3738
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003739#define ALC260_DIGOUT_NID 0x03
3740#define ALC260_DIGIN_NID 0x06
3741
3742static struct hda_input_mux alc260_capture_source = {
3743 .num_items = 4,
3744 .items = {
3745 { "Mic", 0x0 },
3746 { "Front Mic", 0x1 },
3747 { "Line", 0x2 },
3748 { "CD", 0x4 },
3749 },
3750};
3751
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01003752/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003753 * headphone jack and the internal CD lines since these are the only pins at
3754 * which audio can appear. For flexibility, also allow the option of
3755 * recording the mixer output on the second ADC (ADC0 doesn't have a
3756 * connection to the mixer output).
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003757 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003758static struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
3759 {
3760 .num_items = 3,
3761 .items = {
3762 { "Mic/Line", 0x0 },
3763 { "CD", 0x4 },
3764 { "Headphone", 0x2 },
3765 },
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003766 },
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003767 {
3768 .num_items = 4,
3769 .items = {
3770 { "Mic/Line", 0x0 },
3771 { "CD", 0x4 },
3772 { "Headphone", 0x2 },
3773 { "Mixer", 0x5 },
3774 },
3775 },
3776
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003777};
3778
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003779/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
3780 * the Fujitsu S702x, but jacks are marked differently.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01003781 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003782static struct hda_input_mux alc260_acer_capture_sources[2] = {
3783 {
3784 .num_items = 4,
3785 .items = {
3786 { "Mic", 0x0 },
3787 { "Line", 0x2 },
3788 { "CD", 0x4 },
3789 { "Headphone", 0x5 },
3790 },
3791 },
3792 {
3793 .num_items = 5,
3794 .items = {
3795 { "Mic", 0x0 },
3796 { "Line", 0x2 },
3797 { "CD", 0x4 },
3798 { "Headphone", 0x6 },
3799 { "Mixer", 0x5 },
3800 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01003801 },
3802};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003803/*
3804 * This is just place-holder, so there's something for alc_build_pcms to look
3805 * at when it calculates the maximum number of channels. ALC260 has no mixer
3806 * element which allows changing the channel mode, so the verb list is
3807 * never used.
3808 */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01003809static struct hda_channel_mode alc260_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003810 { 2, NULL },
3811};
3812
Kailang Yangdf694da2005-12-05 19:42:22 +01003813
3814/* Mixer combinations
3815 *
3816 * basic: base_output + input + pc_beep + capture
3817 * HP: base_output + input + capture_alt
3818 * HP_3013: hp_3013 + input + capture
3819 * fujitsu: fujitsu + capture
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01003820 * acer: acer + capture
Kailang Yangdf694da2005-12-05 19:42:22 +01003821 */
3822
3823static struct snd_kcontrol_new alc260_base_output_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02003824 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003825 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01003826 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
3827 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
3828 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
3829 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
3830 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003831};
Kailang Yangdf694da2005-12-05 19:42:22 +01003832
3833static struct snd_kcontrol_new alc260_input_mixer[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003834 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
3835 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
3836 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
3837 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
3838 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
3839 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
3840 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
3841 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003842 { } /* end */
3843};
3844
Kailang Yangdf694da2005-12-05 19:42:22 +01003845static struct snd_kcontrol_new alc260_pc_beep_mixer[] = {
3846 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x07, 0x05, HDA_INPUT),
3847 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x07, 0x05, HDA_INPUT),
3848 { } /* end */
3849};
3850
Takashi Iwaibec15c32008-01-28 18:16:30 +01003851/* update HP, line and mono out pins according to the master switch */
3852static void alc260_hp_master_update(struct hda_codec *codec,
3853 hda_nid_t hp, hda_nid_t line,
3854 hda_nid_t mono)
3855{
3856 struct alc_spec *spec = codec->spec;
3857 unsigned int val = spec->master_sw ? PIN_HP : 0;
3858 /* change HP and line-out pins */
3859 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
3860 val);
3861 snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
3862 val);
3863 /* mono (speaker) depending on the HP jack sense */
3864 val = (val && !spec->jack_present) ? PIN_OUT : 0;
3865 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
3866 val);
3867}
3868
3869static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
3870 struct snd_ctl_elem_value *ucontrol)
3871{
3872 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3873 struct alc_spec *spec = codec->spec;
3874 *ucontrol->value.integer.value = spec->master_sw;
3875 return 0;
3876}
3877
3878static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
3879 struct snd_ctl_elem_value *ucontrol)
3880{
3881 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3882 struct alc_spec *spec = codec->spec;
3883 int val = !!*ucontrol->value.integer.value;
3884 hda_nid_t hp, line, mono;
3885
3886 if (val == spec->master_sw)
3887 return 0;
3888 spec->master_sw = val;
3889 hp = (kcontrol->private_value >> 16) & 0xff;
3890 line = (kcontrol->private_value >> 8) & 0xff;
3891 mono = kcontrol->private_value & 0xff;
3892 alc260_hp_master_update(codec, hp, line, mono);
3893 return 1;
3894}
3895
3896static struct snd_kcontrol_new alc260_hp_output_mixer[] = {
3897 {
3898 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3899 .name = "Master Playback Switch",
3900 .info = snd_ctl_boolean_mono_info,
3901 .get = alc260_hp_master_sw_get,
3902 .put = alc260_hp_master_sw_put,
3903 .private_value = (0x0f << 16) | (0x10 << 8) | 0x11
3904 },
3905 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
3906 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
3907 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
3908 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
3909 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
3910 HDA_OUTPUT),
3911 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT),
3912 { } /* end */
3913};
3914
3915static struct hda_verb alc260_hp_unsol_verbs[] = {
3916 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3917 {},
3918};
3919
3920static void alc260_hp_automute(struct hda_codec *codec)
3921{
3922 struct alc_spec *spec = codec->spec;
3923 unsigned int present;
3924
3925 present = snd_hda_codec_read(codec, 0x10, 0,
3926 AC_VERB_GET_PIN_SENSE, 0);
3927 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
3928 alc260_hp_master_update(codec, 0x0f, 0x10, 0x11);
3929}
3930
3931static void alc260_hp_unsol_event(struct hda_codec *codec, unsigned int res)
3932{
3933 if ((res >> 26) == ALC880_HP_EVENT)
3934 alc260_hp_automute(codec);
3935}
3936
Kailang Yangdf694da2005-12-05 19:42:22 +01003937static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01003938 {
3939 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3940 .name = "Master Playback Switch",
3941 .info = snd_ctl_boolean_mono_info,
3942 .get = alc260_hp_master_sw_get,
3943 .put = alc260_hp_master_sw_put,
3944 .private_value = (0x10 << 16) | (0x15 << 8) | 0x11
3945 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003946 HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
3947 HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
3948 HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
3949 HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
3950 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
3951 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01003952 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
3953 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003954 { } /* end */
3955};
3956
Takashi Iwaibec15c32008-01-28 18:16:30 +01003957static struct hda_verb alc260_hp_3013_unsol_verbs[] = {
3958 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3959 {},
3960};
3961
3962static void alc260_hp_3013_automute(struct hda_codec *codec)
3963{
3964 struct alc_spec *spec = codec->spec;
3965 unsigned int present;
3966
3967 present = snd_hda_codec_read(codec, 0x15, 0,
3968 AC_VERB_GET_PIN_SENSE, 0);
3969 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
3970 alc260_hp_master_update(codec, 0x10, 0x15, 0x11);
3971}
3972
3973static void alc260_hp_3013_unsol_event(struct hda_codec *codec,
3974 unsigned int res)
3975{
3976 if ((res >> 26) == ALC880_HP_EVENT)
3977 alc260_hp_3013_automute(codec);
3978}
3979
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003980/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12,
3981 * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10.
3982 */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003983static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003984 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003985 HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003986 ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003987 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
3988 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
3989 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
3990 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003991 ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003992 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
3993 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01003994 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
3995 HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01003996 { } /* end */
3997};
3998
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003999/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current
4000 * versions of the ALC260 don't act on requests to enable mic bias from NID
4001 * 0x0f (used to drive the headphone jack in these laptops). The ALC260
4002 * datasheet doesn't mention this restriction. At this stage it's not clear
4003 * whether this behaviour is intentional or is a hardware bug in chip
4004 * revisions available in early 2006. Therefore for now allow the
4005 * "Headphone Jack Mode" control to span all choices, but if it turns out
4006 * that the lack of mic bias for this NID is intentional we could change the
4007 * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
4008 *
4009 * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
4010 * don't appear to make the mic bias available from the "line" jack, even
4011 * though the NID used for this jack (0x14) can supply it. The theory is
4012 * that perhaps Acer have included blocking capacitors between the ALC260
4013 * and the output jack. If this turns out to be the case for all such
4014 * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
4015 * to ALC_PIN_DIR_INOUT_NOMICBIAS.
Jonathan Woithebd869482006-11-28 11:35:52 +01004016 *
4017 * The C20x Tablet series have a mono internal speaker which is controlled
4018 * via the chip's Mono sum widget and pin complex, so include the necessary
4019 * controls for such models. On models without a "mono speaker" the control
4020 * won't do anything.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004021 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004022static struct snd_kcontrol_new alc260_acer_mixer[] = {
4023 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4024 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004025 ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004026 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
Jonathan Woithebd869482006-11-28 11:35:52 +01004027 HDA_OUTPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004028 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2,
Jonathan Woithebd869482006-11-28 11:35:52 +01004029 HDA_INPUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004030 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4031 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4032 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4033 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4034 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4035 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4036 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4037 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4038 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4039 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
4040 { } /* end */
4041};
4042
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004043/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
4044 * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17.
4045 */
4046static struct snd_kcontrol_new alc260_will_mixer[] = {
4047 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4048 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
4049 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4050 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4051 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4052 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4053 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4054 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4055 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4056 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4057 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4058 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
4059 { } /* end */
4060};
4061
4062/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
4063 * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
4064 */
4065static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
4066 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4067 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
4068 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4069 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4070 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4071 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
4072 HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
4073 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4074 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4075 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4076 { } /* end */
4077};
4078
Kailang Yangdf694da2005-12-05 19:42:22 +01004079/* capture mixer elements */
4080static struct snd_kcontrol_new alc260_capture_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004081 HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT),
4082 HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01004083 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x05, 0x0, HDA_INPUT),
4084 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x05, 0x0, HDA_INPUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004085 {
4086 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Kailang Yangdf694da2005-12-05 19:42:22 +01004087 /* The multiple "Capture Source" controls confuse alsamixer
4088 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01004089 */
4090 /* .name = "Capture Source", */
4091 .name = "Input Source",
4092 .count = 2,
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004093 .info = alc_mux_enum_info,
4094 .get = alc_mux_enum_get,
4095 .put = alc_mux_enum_put,
4096 },
4097 { } /* end */
4098};
4099
Kailang Yangdf694da2005-12-05 19:42:22 +01004100static struct snd_kcontrol_new alc260_capture_alt_mixer[] = {
4101 HDA_CODEC_VOLUME("Capture Volume", 0x05, 0x0, HDA_INPUT),
4102 HDA_CODEC_MUTE("Capture Switch", 0x05, 0x0, HDA_INPUT),
4103 {
4104 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4105 /* The multiple "Capture Source" controls confuse alsamixer
4106 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01004107 */
4108 /* .name = "Capture Source", */
4109 .name = "Input Source",
4110 .count = 1,
4111 .info = alc_mux_enum_info,
4112 .get = alc_mux_enum_get,
4113 .put = alc_mux_enum_put,
4114 },
4115 { } /* end */
4116};
4117
4118/*
4119 * initialization verbs
4120 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004121static struct hda_verb alc260_init_verbs[] = {
4122 /* Line In pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02004123 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004124 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02004125 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004126 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02004127 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004128 /* Mic2 (front panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02004129 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004130 /* LINE-2 is used for line-out in rear */
Takashi Iwai05acb862005-06-10 19:50:25 +02004131 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004132 /* select line-out */
Jonathan Woithefd56f2d2006-01-24 10:35:46 +01004133 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004134 /* LINE-OUT pin */
Takashi Iwai05acb862005-06-10 19:50:25 +02004135 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004136 /* enable HP */
Takashi Iwai05acb862005-06-10 19:50:25 +02004137 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138 /* enable Mono */
Takashi Iwai05acb862005-06-10 19:50:25 +02004139 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4140 /* mute capture amp left and right */
Takashi Iwai16ded522005-06-10 19:58:24 +02004141 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004142 /* set connection select to line in (default select for this ADC) */
4143 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai16ded522005-06-10 19:58:24 +02004144 /* mute capture amp left and right */
4145 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4146 /* set connection select to line in (default select for this ADC) */
4147 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai05acb862005-06-10 19:50:25 +02004148 /* set vol=0 Line-Out mixer amp left and right */
4149 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4150 /* unmute pin widget amp left and right (no gain on this amp) */
4151 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4152 /* set vol=0 HP mixer amp left and right */
4153 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4154 /* unmute pin widget amp left and right (no gain on this amp) */
4155 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4156 /* set vol=0 Mono mixer amp left and right */
4157 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4158 /* unmute pin widget amp left and right (no gain on this amp) */
4159 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4160 /* unmute LINE-2 out pin */
4161 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004162 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4163 * Line In 2 = 0x03
4164 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004165 /* mute analog inputs */
4166 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4167 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4168 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4169 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4170 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004171 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004172 /* mute Front out path */
4173 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4174 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4175 /* mute Headphone out path */
4176 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4177 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4178 /* mute Mono out path */
4179 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4180 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181 { }
4182};
4183
Takashi Iwai474167d2006-05-17 17:17:43 +02004184#if 0 /* should be identical with alc260_init_verbs? */
Kailang Yangdf694da2005-12-05 19:42:22 +01004185static struct hda_verb alc260_hp_init_verbs[] = {
4186 /* Headphone and output */
4187 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
4188 /* mono output */
4189 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4190 /* Mic1 (rear panel) pin widget for input and vref at 80% */
4191 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4192 /* Mic2 (front panel) pin widget for input and vref at 80% */
4193 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4194 /* Line In pin widget for input */
4195 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4196 /* Line-2 pin widget for output */
4197 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4198 /* CD pin widget for input */
4199 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4200 /* unmute amp left and right */
4201 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
4202 /* set connection select to line in (default select for this ADC) */
4203 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
4204 /* unmute Line-Out mixer amp left and right (volume = 0) */
4205 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4206 /* mute pin widget amp left and right (no gain on this amp) */
4207 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
4208 /* unmute HP mixer amp left and right (volume = 0) */
4209 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4210 /* mute pin widget amp left and right (no gain on this amp) */
4211 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004212 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4213 * Line In 2 = 0x03
4214 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004215 /* mute analog inputs */
4216 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4217 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4218 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4219 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4220 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01004221 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
4222 /* Unmute Front out path */
4223 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4224 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4225 /* Unmute Headphone out path */
4226 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4227 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4228 /* Unmute Mono out path */
4229 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4230 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4231 { }
4232};
Takashi Iwai474167d2006-05-17 17:17:43 +02004233#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01004234
4235static struct hda_verb alc260_hp_3013_init_verbs[] = {
4236 /* Line out and output */
4237 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4238 /* mono output */
4239 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4240 /* Mic1 (rear panel) pin widget for input and vref at 80% */
4241 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4242 /* Mic2 (front panel) pin widget for input and vref at 80% */
4243 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4244 /* Line In pin widget for input */
4245 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4246 /* Headphone pin widget for output */
4247 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
4248 /* CD pin widget for input */
4249 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4250 /* unmute amp left and right */
4251 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
4252 /* set connection select to line in (default select for this ADC) */
4253 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
4254 /* unmute Line-Out mixer amp left and right (volume = 0) */
4255 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4256 /* mute pin widget amp left and right (no gain on this amp) */
4257 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
4258 /* unmute HP mixer amp left and right (volume = 0) */
4259 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4260 /* mute pin widget amp left and right (no gain on this amp) */
4261 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004262 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4263 * Line In 2 = 0x03
4264 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004265 /* mute analog inputs */
4266 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4267 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4268 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4269 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4270 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01004271 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
4272 /* Unmute Front out path */
4273 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4274 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4275 /* Unmute Headphone out path */
4276 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4277 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4278 /* Unmute Mono out path */
4279 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4280 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4281 { }
4282};
4283
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004284/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004285 * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
4286 * audio = 0x16, internal speaker = 0x10.
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004287 */
4288static struct hda_verb alc260_fujitsu_init_verbs[] = {
4289 /* Disable all GPIOs */
4290 {0x01, AC_VERB_SET_GPIO_MASK, 0},
4291 /* Internal speaker is connected to headphone pin */
4292 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4293 /* Headphone/Line-out jack connects to Line1 pin; make it an output */
4294 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004295 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
4296 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4297 /* Ensure all other unused pins are disabled and muted. */
4298 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4299 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004300 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004301 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004302 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004303 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4304 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4305 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004306
Jonathan Woithef7ace402006-02-28 11:46:14 +01004307 /* Disable digital (SPDIF) pins */
4308 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
4309 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004310
Jonathan Woithef7ace402006-02-28 11:46:14 +01004311 /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
4312 * when acting as an output.
4313 */
4314 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
4315
4316 /* Start with output sum widgets muted and their output gains at min */
Takashi Iwai8b33a5a2006-02-09 11:57:01 +01004317 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4318 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4319 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4320 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4321 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4322 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4323 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4324 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4325 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004326
Jonathan Woithef7ace402006-02-28 11:46:14 +01004327 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
4328 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4329 /* Unmute Line1 pin widget output buffer since it starts as an output.
4330 * If the pin mode is changed by the user the pin mode control will
4331 * take care of enabling the pin's input/output buffers as needed.
4332 * Therefore there's no need to enable the input buffer at this
4333 * stage.
Jonathan Woithecdcd9262006-02-28 11:36:42 +01004334 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01004335 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithecdcd9262006-02-28 11:36:42 +01004336 /* Unmute input buffer of pin widget used for Line-in (no equiv
4337 * mixer ctrl)
4338 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01004339 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004340
Jonathan Woithef7ace402006-02-28 11:46:14 +01004341 /* Mute capture amp left and right */
4342 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4343 /* Set ADC connection select to match default mixer setting - line
4344 * in (on mic1 pin)
4345 */
4346 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004347
Jonathan Woithef7ace402006-02-28 11:46:14 +01004348 /* Do the same for the second ADC: mute capture input amp and
4349 * set ADC connection to line in (on mic1 pin)
4350 */
4351 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4352 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004353
Jonathan Woithef7ace402006-02-28 11:46:14 +01004354 /* Mute all inputs to mixer widget (even unconnected ones) */
4355 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
4356 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
4357 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
4358 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
4359 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
4360 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
4361 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
4362 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
Takashi Iwai4a471b72005-12-07 13:56:29 +01004363
4364 { }
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004365};
4366
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004367/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
4368 * similar laptops (adapted from Fujitsu init verbs).
4369 */
4370static struct hda_verb alc260_acer_init_verbs[] = {
4371 /* On TravelMate laptops, GPIO 0 enables the internal speaker and
4372 * the headphone jack. Turn this on and rely on the standard mute
4373 * methods whenever the user wants to turn these outputs off.
4374 */
4375 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
4376 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
4377 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
4378 /* Internal speaker/Headphone jack is connected to Line-out pin */
4379 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4380 /* Internal microphone/Mic jack is connected to Mic1 pin */
4381 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
4382 /* Line In jack is connected to Line1 pin */
4383 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Jonathan Woithebd869482006-11-28 11:35:52 +01004384 /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
4385 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004386 /* Ensure all other unused pins are disabled and muted. */
4387 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4388 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004389 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4390 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4391 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4392 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4393 /* Disable digital (SPDIF) pins */
4394 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
4395 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
4396
4397 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
4398 * bus when acting as outputs.
4399 */
4400 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
4401 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
4402
4403 /* Start with output sum widgets muted and their output gains at min */
4404 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4405 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4406 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4407 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4408 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4409 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4410 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4411 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4412 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4413
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004414 /* Unmute Line-out pin widget amp left and right
4415 * (no equiv mixer ctrl)
4416 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004417 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithebd869482006-11-28 11:35:52 +01004418 /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
4419 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004420 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
4421 * inputs. If the pin mode is changed by the user the pin mode control
4422 * will take care of enabling the pin's input/output buffers as needed.
4423 * Therefore there's no need to enable the input buffer at this
4424 * stage.
4425 */
4426 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4427 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4428
4429 /* Mute capture amp left and right */
4430 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4431 /* Set ADC connection select to match default mixer setting - mic
4432 * (on mic1 pin)
4433 */
4434 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
4435
4436 /* Do similar with the second ADC: mute capture input amp and
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004437 * set ADC connection to mic to match ALSA's default state.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004438 */
4439 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004440 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004441
4442 /* Mute all inputs to mixer widget (even unconnected ones) */
4443 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
4444 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
4445 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
4446 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
4447 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
4448 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
4449 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
4450 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
4451
4452 { }
4453};
4454
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004455static struct hda_verb alc260_will_verbs[] = {
4456 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4457 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
4458 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
4459 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
4460 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
4461 {0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
4462 {}
4463};
4464
4465static struct hda_verb alc260_replacer_672v_verbs[] = {
4466 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
4467 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
4468 {0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
4469
4470 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
4471 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
4472 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
4473
4474 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4475 {}
4476};
4477
4478/* toggle speaker-output according to the hp-jack state */
4479static void alc260_replacer_672v_automute(struct hda_codec *codec)
4480{
4481 unsigned int present;
4482
4483 /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
4484 present = snd_hda_codec_read(codec, 0x0f, 0,
4485 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
4486 if (present) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004487 snd_hda_codec_write_cache(codec, 0x01, 0,
4488 AC_VERB_SET_GPIO_DATA, 1);
4489 snd_hda_codec_write_cache(codec, 0x0f, 0,
4490 AC_VERB_SET_PIN_WIDGET_CONTROL,
4491 PIN_HP);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004492 } else {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004493 snd_hda_codec_write_cache(codec, 0x01, 0,
4494 AC_VERB_SET_GPIO_DATA, 0);
4495 snd_hda_codec_write_cache(codec, 0x0f, 0,
4496 AC_VERB_SET_PIN_WIDGET_CONTROL,
4497 PIN_OUT);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004498 }
4499}
4500
4501static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
4502 unsigned int res)
4503{
4504 if ((res >> 26) == ALC880_HP_EVENT)
4505 alc260_replacer_672v_automute(codec);
4506}
4507
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004508/* Test configuration for debugging, modelled after the ALC880 test
4509 * configuration.
4510 */
4511#ifdef CONFIG_SND_DEBUG
4512static hda_nid_t alc260_test_dac_nids[1] = {
4513 0x02,
4514};
4515static hda_nid_t alc260_test_adc_nids[2] = {
4516 0x04, 0x05,
4517};
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004518/* For testing the ALC260, each input MUX needs its own definition since
4519 * the signal assignments are different. This assumes that the first ADC
4520 * is NID 0x04.
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01004521 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004522static struct hda_input_mux alc260_test_capture_sources[2] = {
4523 {
4524 .num_items = 7,
4525 .items = {
4526 { "MIC1 pin", 0x0 },
4527 { "MIC2 pin", 0x1 },
4528 { "LINE1 pin", 0x2 },
4529 { "LINE2 pin", 0x3 },
4530 { "CD pin", 0x4 },
4531 { "LINE-OUT pin", 0x5 },
4532 { "HP-OUT pin", 0x6 },
4533 },
4534 },
4535 {
4536 .num_items = 8,
4537 .items = {
4538 { "MIC1 pin", 0x0 },
4539 { "MIC2 pin", 0x1 },
4540 { "LINE1 pin", 0x2 },
4541 { "LINE2 pin", 0x3 },
4542 { "CD pin", 0x4 },
4543 { "Mixer", 0x5 },
4544 { "LINE-OUT pin", 0x6 },
4545 { "HP-OUT pin", 0x7 },
4546 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004547 },
4548};
4549static struct snd_kcontrol_new alc260_test_mixer[] = {
4550 /* Output driver widgets */
4551 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
4552 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
4553 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4554 HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
4555 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4556 HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
4557
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004558 /* Modes for retasking pin widgets
4559 * Note: the ALC260 doesn't seem to act on requests to enable mic
4560 * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't
4561 * mention this restriction. At this stage it's not clear whether
4562 * this behaviour is intentional or is a hardware bug in chip
4563 * revisions available at least up until early 2006. Therefore for
4564 * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
4565 * choices, but if it turns out that the lack of mic bias for these
4566 * NIDs is intentional we could change their modes from
4567 * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
4568 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004569 ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
4570 ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
4571 ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
4572 ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
4573 ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
4574 ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
4575
4576 /* Loopback mixer controls */
4577 HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
4578 HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
4579 HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
4580 HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
4581 HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
4582 HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
4583 HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
4584 HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
4585 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4586 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4587 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4588 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
4589 HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
4590 HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
4591 HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
4592 HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01004593
4594 /* Controls for GPIO pins, assuming they are configured as outputs */
4595 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
4596 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
4597 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
4598 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
4599
Jonathan Woithe92621f12006-02-28 11:47:47 +01004600 /* Switches to allow the digital IO pins to be enabled. The datasheet
4601 * is ambigious as to which NID is which; testing on laptops which
4602 * make this output available should provide clarification.
4603 */
4604 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
4605 ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
4606
Jonathan Woithef8225f62008-01-08 12:16:54 +01004607 /* A switch allowing EAPD to be enabled. Some laptops seem to use
4608 * this output to turn on an external amplifier.
4609 */
4610 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
4611 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
4612
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004613 { } /* end */
4614};
4615static struct hda_verb alc260_test_init_verbs[] = {
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01004616 /* Enable all GPIOs as outputs with an initial value of 0 */
4617 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
4618 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
4619 {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
4620
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004621 /* Enable retasking pins as output, initially without power amp */
4622 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4623 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4624 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4625 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4626 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4627 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4628
Jonathan Woithe92621f12006-02-28 11:47:47 +01004629 /* Disable digital (SPDIF) pins initially, but users can enable
4630 * them via a mixer switch. In the case of SPDIF-out, this initverb
4631 * payload also sets the generation to 0, output to be in "consumer"
4632 * PCM format, copyright asserted, no pre-emphasis and no validity
4633 * control.
4634 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004635 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
4636 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
4637
Jonathan Woithef7ace402006-02-28 11:46:14 +01004638 /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004639 * OUT1 sum bus when acting as an output.
4640 */
4641 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
4642 {0x0c, AC_VERB_SET_CONNECT_SEL, 0},
4643 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
4644 {0x0e, AC_VERB_SET_CONNECT_SEL, 0},
4645
4646 /* Start with output sum widgets muted and their output gains at min */
4647 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4648 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4649 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4650 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4651 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4652 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4653 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4654 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4655 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4656
Jonathan Woithecdcd9262006-02-28 11:36:42 +01004657 /* Unmute retasking pin widget output buffers since the default
4658 * state appears to be output. As the pin mode is changed by the
4659 * user the pin mode control will take care of enabling the pin's
4660 * input/output buffers as needed.
4661 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004662 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4663 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4664 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4665 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4666 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4667 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4668 /* Also unmute the mono-out pin widget */
4669 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4670
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004671 /* Mute capture amp left and right */
4672 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004673 /* Set ADC connection select to match default mixer setting (mic1
4674 * pin)
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004675 */
4676 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
4677
4678 /* Do the same for the second ADC: mute capture input amp and
Jonathan Woithef7ace402006-02-28 11:46:14 +01004679 * set ADC connection to mic1 pin
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004680 */
4681 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4682 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
4683
4684 /* Mute all inputs to mixer widget (even unconnected ones) */
4685 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
4686 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
4687 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
4688 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
4689 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
4690 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
4691 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
4692 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
4693
4694 { }
4695};
4696#endif
4697
Takashi Iwai63300792008-01-24 15:31:36 +01004698#define alc260_pcm_analog_playback alc880_pcm_analog_alt_playback
4699#define alc260_pcm_analog_capture alc880_pcm_analog_capture
Linus Torvalds1da177e2005-04-16 15:20:36 -07004700
Takashi Iwaia3bcba32005-12-06 19:05:29 +01004701#define alc260_pcm_digital_playback alc880_pcm_digital_playback
4702#define alc260_pcm_digital_capture alc880_pcm_digital_capture
4703
Kailang Yangdf694da2005-12-05 19:42:22 +01004704/*
4705 * for BIOS auto-configuration
4706 */
4707
4708static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
4709 const char *pfx)
4710{
4711 hda_nid_t nid_vol;
4712 unsigned long vol_val, sw_val;
4713 char name[32];
4714 int err;
4715
4716 if (nid >= 0x0f && nid < 0x11) {
4717 nid_vol = nid - 0x7;
4718 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
4719 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
4720 } else if (nid == 0x11) {
4721 nid_vol = nid - 0x7;
4722 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT);
4723 sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
4724 } else if (nid >= 0x12 && nid <= 0x15) {
4725 nid_vol = 0x08;
4726 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
4727 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
4728 } else
4729 return 0; /* N/A */
4730
4731 snprintf(name, sizeof(name), "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004732 err = add_control(spec, ALC_CTL_WIDGET_VOL, name, vol_val);
4733 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01004734 return err;
4735 snprintf(name, sizeof(name), "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004736 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, sw_val);
4737 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01004738 return err;
4739 return 1;
4740}
4741
4742/* add playback controls from the parsed DAC table */
4743static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
4744 const struct auto_pin_cfg *cfg)
4745{
4746 hda_nid_t nid;
4747 int err;
4748
4749 spec->multiout.num_dacs = 1;
4750 spec->multiout.dac_nids = spec->private_dac_nids;
4751 spec->multiout.dac_nids[0] = 0x02;
4752
4753 nid = cfg->line_out_pins[0];
4754 if (nid) {
4755 err = alc260_add_playback_controls(spec, nid, "Front");
4756 if (err < 0)
4757 return err;
4758 }
4759
Takashi Iwai82bc9552006-03-21 11:24:42 +01004760 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01004761 if (nid) {
4762 err = alc260_add_playback_controls(spec, nid, "Speaker");
4763 if (err < 0)
4764 return err;
4765 }
4766
Takashi Iwaieb06ed82006-09-20 17:10:27 +02004767 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01004768 if (nid) {
4769 err = alc260_add_playback_controls(spec, nid, "Headphone");
4770 if (err < 0)
4771 return err;
4772 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004773 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01004774}
4775
4776/* create playback/capture controls for input pins */
4777static int alc260_auto_create_analog_input_ctls(struct alc_spec *spec,
4778 const struct auto_pin_cfg *cfg)
4779{
Kailang Yangdf694da2005-12-05 19:42:22 +01004780 struct hda_input_mux *imux = &spec->private_imux;
4781 int i, err, idx;
4782
4783 for (i = 0; i < AUTO_PIN_LAST; i++) {
4784 if (cfg->input_pins[i] >= 0x12) {
4785 idx = cfg->input_pins[i] - 0x12;
Takashi Iwai4a471b72005-12-07 13:56:29 +01004786 err = new_analog_input(spec, cfg->input_pins[i],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004787 auto_pin_cfg_labels[i], idx,
4788 0x07);
Kailang Yangdf694da2005-12-05 19:42:22 +01004789 if (err < 0)
4790 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004791 imux->items[imux->num_items].label =
4792 auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +01004793 imux->items[imux->num_items].index = idx;
4794 imux->num_items++;
4795 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004796 if (cfg->input_pins[i] >= 0x0f && cfg->input_pins[i] <= 0x10){
Kailang Yangdf694da2005-12-05 19:42:22 +01004797 idx = cfg->input_pins[i] - 0x09;
Takashi Iwai4a471b72005-12-07 13:56:29 +01004798 err = new_analog_input(spec, cfg->input_pins[i],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004799 auto_pin_cfg_labels[i], idx,
4800 0x07);
Kailang Yangdf694da2005-12-05 19:42:22 +01004801 if (err < 0)
4802 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004803 imux->items[imux->num_items].label =
4804 auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +01004805 imux->items[imux->num_items].index = idx;
4806 imux->num_items++;
4807 }
4808 }
4809 return 0;
4810}
4811
4812static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
4813 hda_nid_t nid, int pin_type,
4814 int sel_idx)
4815{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004816 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01004817 /* need the manual connection? */
4818 if (nid >= 0x12) {
4819 int idx = nid - 0x12;
4820 snd_hda_codec_write(codec, idx + 0x0b, 0,
4821 AC_VERB_SET_CONNECT_SEL, sel_idx);
Kailang Yangdf694da2005-12-05 19:42:22 +01004822 }
4823}
4824
4825static void alc260_auto_init_multi_out(struct hda_codec *codec)
4826{
4827 struct alc_spec *spec = codec->spec;
4828 hda_nid_t nid;
4829
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004830 alc_subsystem_id(codec, 0x10, 0x15, 0x0f);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004831 nid = spec->autocfg.line_out_pins[0];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02004832 if (nid) {
4833 int pin_type = get_pin_type(spec->autocfg.line_out_type);
4834 alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
4835 }
Kailang Yangdf694da2005-12-05 19:42:22 +01004836
Takashi Iwai82bc9552006-03-21 11:24:42 +01004837 nid = spec->autocfg.speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01004838 if (nid)
4839 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
4840
Takashi Iwaieb06ed82006-09-20 17:10:27 +02004841 nid = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01004842 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02004843 alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004844}
Kailang Yangdf694da2005-12-05 19:42:22 +01004845
4846#define ALC260_PIN_CD_NID 0x16
4847static void alc260_auto_init_analog_input(struct hda_codec *codec)
4848{
4849 struct alc_spec *spec = codec->spec;
4850 int i;
4851
4852 for (i = 0; i < AUTO_PIN_LAST; i++) {
4853 hda_nid_t nid = spec->autocfg.input_pins[i];
4854 if (nid >= 0x12) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004855 snd_hda_codec_write(codec, nid, 0,
4856 AC_VERB_SET_PIN_WIDGET_CONTROL,
4857 i <= AUTO_PIN_FRONT_MIC ?
4858 PIN_VREF80 : PIN_IN);
Kailang Yangdf694da2005-12-05 19:42:22 +01004859 if (nid != ALC260_PIN_CD_NID)
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004860 snd_hda_codec_write(codec, nid, 0,
4861 AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangdf694da2005-12-05 19:42:22 +01004862 AMP_OUT_MUTE);
4863 }
4864 }
4865}
4866
4867/*
4868 * generic initialization of ADC, input mixers and output mixers
4869 */
4870static struct hda_verb alc260_volume_init_verbs[] = {
4871 /*
4872 * Unmute ADC0-1 and set the default input to mic-in
4873 */
4874 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
4875 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4876 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
4877 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4878
4879 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
4880 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004881 * Note: PASD motherboards uses the Line In 2 as the input for
4882 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01004883 */
4884 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004885 /* mute analog inputs */
4886 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4887 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4888 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4889 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4890 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01004891
4892 /*
4893 * Set up output mixers (0x08 - 0x0a)
4894 */
4895 /* set vol=0 to output mixers */
4896 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4897 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4898 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4899 /* set up input amps for analog loopback */
4900 /* Amp Indices: DAC = 0, mixer = 1 */
4901 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4902 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4903 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4904 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4905 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4906 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4907
4908 { }
4909};
4910
4911static int alc260_parse_auto_config(struct hda_codec *codec)
4912{
4913 struct alc_spec *spec = codec->spec;
4914 unsigned int wcap;
4915 int err;
4916 static hda_nid_t alc260_ignore[] = { 0x17, 0 };
4917
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004918 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
4919 alc260_ignore);
4920 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01004921 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004922 err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
4923 if (err < 0)
Takashi Iwai4a471b72005-12-07 13:56:29 +01004924 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004925 if (!spec->kctl_alloc)
Kailang Yangdf694da2005-12-05 19:42:22 +01004926 return 0; /* can't find valid BIOS pin config */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004927 err = alc260_auto_create_analog_input_ctls(spec, &spec->autocfg);
4928 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01004929 return err;
4930
4931 spec->multiout.max_channels = 2;
4932
4933 if (spec->autocfg.dig_out_pin)
4934 spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
4935 if (spec->kctl_alloc)
4936 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
4937
4938 spec->init_verbs[spec->num_init_verbs++] = alc260_volume_init_verbs;
4939
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004940 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +01004941 spec->input_mux = &spec->private_imux;
4942
4943 /* check whether NID 0x04 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +01004944 wcap = get_wcaps(codec, 0x04);
Kailang Yangdf694da2005-12-05 19:42:22 +01004945 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */
4946 if (wcap != AC_WID_AUD_IN) {
4947 spec->adc_nids = alc260_adc_nids_alt;
4948 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
4949 spec->mixers[spec->num_mixers] = alc260_capture_alt_mixer;
Kailang Yangdf694da2005-12-05 19:42:22 +01004950 } else {
4951 spec->adc_nids = alc260_adc_nids;
4952 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
4953 spec->mixers[spec->num_mixers] = alc260_capture_mixer;
Kailang Yangdf694da2005-12-05 19:42:22 +01004954 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01004955 spec->num_mixers++;
Kailang Yangdf694da2005-12-05 19:42:22 +01004956
4957 return 1;
4958}
4959
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004960/* additional initialization for auto-configuration model */
4961static void alc260_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01004962{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004963 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01004964 alc260_auto_init_multi_out(codec);
4965 alc260_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004966 if (spec->unsol_event)
4967 alc_sku_automute(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01004968}
4969
Takashi Iwaicb53c622007-08-10 17:21:45 +02004970#ifdef CONFIG_SND_HDA_POWER_SAVE
4971static struct hda_amp_list alc260_loopbacks[] = {
4972 { 0x07, HDA_INPUT, 0 },
4973 { 0x07, HDA_INPUT, 1 },
4974 { 0x07, HDA_INPUT, 2 },
4975 { 0x07, HDA_INPUT, 3 },
4976 { 0x07, HDA_INPUT, 4 },
4977 { } /* end */
4978};
4979#endif
4980
Kailang Yangdf694da2005-12-05 19:42:22 +01004981/*
4982 * ALC260 configurations
4983 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004984static const char *alc260_models[ALC260_MODEL_LAST] = {
4985 [ALC260_BASIC] = "basic",
4986 [ALC260_HP] = "hp",
4987 [ALC260_HP_3013] = "hp-3013",
4988 [ALC260_FUJITSU_S702X] = "fujitsu",
4989 [ALC260_ACER] = "acer",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004990 [ALC260_WILL] = "will",
4991 [ALC260_REPLACER_672V] = "replacer",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004992#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004993 [ALC260_TEST] = "test",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004994#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004995 [ALC260_AUTO] = "auto",
4996};
4997
4998static struct snd_pci_quirk alc260_cfg_tbl[] = {
Jonathan Woithebd869482006-11-28 11:35:52 +01004999 SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005000 SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
Takashi Iwai9720b712007-03-13 21:46:23 +01005001 SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
Takashi Iwaia8a5d062007-03-15 15:10:28 +01005002 SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_HP_3013),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005003 SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
5004 SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP),
5005 SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_3013),
5006 SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
5007 SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
5008 SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
5009 SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
5010 SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
5011 SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
5012 SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
5013 SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
5014 SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005015 SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01005016 SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
Takashi Iwai16ded522005-06-10 19:58:24 +02005017 {}
5018};
5019
Kailang Yangdf694da2005-12-05 19:42:22 +01005020static struct alc_config_preset alc260_presets[] = {
5021 [ALC260_BASIC] = {
5022 .mixers = { alc260_base_output_mixer,
5023 alc260_input_mixer,
5024 alc260_pc_beep_mixer,
5025 alc260_capture_mixer },
5026 .init_verbs = { alc260_init_verbs },
5027 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5028 .dac_nids = alc260_dac_nids,
5029 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
5030 .adc_nids = alc260_adc_nids,
5031 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5032 .channel_mode = alc260_modes,
5033 .input_mux = &alc260_capture_source,
5034 },
5035 [ALC260_HP] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01005036 .mixers = { alc260_hp_output_mixer,
Kailang Yangdf694da2005-12-05 19:42:22 +01005037 alc260_input_mixer,
5038 alc260_capture_alt_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01005039 .init_verbs = { alc260_init_verbs,
5040 alc260_hp_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01005041 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5042 .dac_nids = alc260_dac_nids,
5043 .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
5044 .adc_nids = alc260_hp_adc_nids,
5045 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5046 .channel_mode = alc260_modes,
5047 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005048 .unsol_event = alc260_hp_unsol_event,
5049 .init_hook = alc260_hp_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01005050 },
5051 [ALC260_HP_3013] = {
5052 .mixers = { alc260_hp_3013_mixer,
5053 alc260_input_mixer,
5054 alc260_capture_alt_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01005055 .init_verbs = { alc260_hp_3013_init_verbs,
5056 alc260_hp_3013_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01005057 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5058 .dac_nids = alc260_dac_nids,
5059 .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
5060 .adc_nids = alc260_hp_adc_nids,
5061 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5062 .channel_mode = alc260_modes,
5063 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005064 .unsol_event = alc260_hp_3013_unsol_event,
5065 .init_hook = alc260_hp_3013_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01005066 },
5067 [ALC260_FUJITSU_S702X] = {
5068 .mixers = { alc260_fujitsu_mixer,
5069 alc260_capture_mixer },
5070 .init_verbs = { alc260_fujitsu_init_verbs },
5071 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5072 .dac_nids = alc260_dac_nids,
Jonathan Woithed57fdac2006-02-28 11:38:35 +01005073 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
5074 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01005075 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5076 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005077 .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
5078 .input_mux = alc260_fujitsu_capture_sources,
Kailang Yangdf694da2005-12-05 19:42:22 +01005079 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005080 [ALC260_ACER] = {
5081 .mixers = { alc260_acer_mixer,
5082 alc260_capture_mixer },
5083 .init_verbs = { alc260_acer_init_verbs },
5084 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5085 .dac_nids = alc260_dac_nids,
5086 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
5087 .adc_nids = alc260_dual_adc_nids,
5088 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5089 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005090 .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
5091 .input_mux = alc260_acer_capture_sources,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005092 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005093 [ALC260_WILL] = {
5094 .mixers = { alc260_will_mixer,
5095 alc260_capture_mixer },
5096 .init_verbs = { alc260_init_verbs, alc260_will_verbs },
5097 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5098 .dac_nids = alc260_dac_nids,
5099 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
5100 .adc_nids = alc260_adc_nids,
5101 .dig_out_nid = ALC260_DIGOUT_NID,
5102 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5103 .channel_mode = alc260_modes,
5104 .input_mux = &alc260_capture_source,
5105 },
5106 [ALC260_REPLACER_672V] = {
5107 .mixers = { alc260_replacer_672v_mixer,
5108 alc260_capture_mixer },
5109 .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
5110 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5111 .dac_nids = alc260_dac_nids,
5112 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
5113 .adc_nids = alc260_adc_nids,
5114 .dig_out_nid = ALC260_DIGOUT_NID,
5115 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5116 .channel_mode = alc260_modes,
5117 .input_mux = &alc260_capture_source,
5118 .unsol_event = alc260_replacer_672v_unsol_event,
5119 .init_hook = alc260_replacer_672v_automute,
5120 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005121#ifdef CONFIG_SND_DEBUG
5122 [ALC260_TEST] = {
5123 .mixers = { alc260_test_mixer,
5124 alc260_capture_mixer },
5125 .init_verbs = { alc260_test_init_verbs },
5126 .num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
5127 .dac_nids = alc260_test_dac_nids,
5128 .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
5129 .adc_nids = alc260_test_adc_nids,
5130 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5131 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005132 .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
5133 .input_mux = alc260_test_capture_sources,
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005134 },
5135#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01005136};
5137
Linus Torvalds1da177e2005-04-16 15:20:36 -07005138static int patch_alc260(struct hda_codec *codec)
5139{
5140 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01005141 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005142
Takashi Iwaie560d8d2005-09-09 14:21:46 +02005143 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005144 if (spec == NULL)
5145 return -ENOMEM;
5146
5147 codec->spec = spec;
5148
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005149 board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
5150 alc260_models,
5151 alc260_cfg_tbl);
5152 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02005153 snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260, "
5154 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01005155 board_config = ALC260_AUTO;
Takashi Iwai16ded522005-06-10 19:58:24 +02005156 }
5157
Kailang Yangdf694da2005-12-05 19:42:22 +01005158 if (board_config == ALC260_AUTO) {
5159 /* automatic parse from the BIOS config */
5160 err = alc260_parse_auto_config(codec);
5161 if (err < 0) {
5162 alc_free(codec);
5163 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005164 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02005165 printk(KERN_INFO
5166 "hda_codec: Cannot set up configuration "
5167 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01005168 board_config = ALC260_BASIC;
5169 }
Takashi Iwai16ded522005-06-10 19:58:24 +02005170 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005171
Kailang Yangdf694da2005-12-05 19:42:22 +01005172 if (board_config != ALC260_AUTO)
5173 setup_preset(spec, &alc260_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005174
5175 spec->stream_name_analog = "ALC260 Analog";
5176 spec->stream_analog_playback = &alc260_pcm_analog_playback;
5177 spec->stream_analog_capture = &alc260_pcm_analog_capture;
5178
Takashi Iwaia3bcba32005-12-06 19:05:29 +01005179 spec->stream_name_digital = "ALC260 Digital";
5180 spec->stream_digital_playback = &alc260_pcm_digital_playback;
5181 spec->stream_digital_capture = &alc260_pcm_digital_capture;
5182
Takashi Iwai2134ea42008-01-10 16:53:55 +01005183 spec->vmaster_nid = 0x08;
5184
Linus Torvalds1da177e2005-04-16 15:20:36 -07005185 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01005186 if (board_config == ALC260_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005187 spec->init_hook = alc260_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02005188#ifdef CONFIG_SND_HDA_POWER_SAVE
5189 if (!spec->loopback.amplist)
5190 spec->loopback.amplist = alc260_loopbacks;
5191#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005192
5193 return 0;
5194}
5195
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005196
Linus Torvalds1da177e2005-04-16 15:20:36 -07005197/*
5198 * ALC882 support
5199 *
5200 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
5201 * configuration. Each pin widget can choose any input DACs and a mixer.
5202 * Each ADC is connected from a mixer of all inputs. This makes possible
5203 * 6-channel independent captures.
5204 *
5205 * In addition, an independent DAC for the multi-playback (not used in this
5206 * driver yet).
5207 */
Kailang Yangdf694da2005-12-05 19:42:22 +01005208#define ALC882_DIGOUT_NID 0x06
5209#define ALC882_DIGIN_NID 0x0a
Linus Torvalds1da177e2005-04-16 15:20:36 -07005210
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01005211static struct hda_channel_mode alc882_ch_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005212 { 8, NULL }
5213};
5214
5215static hda_nid_t alc882_dac_nids[4] = {
5216 /* front, rear, clfe, rear_surr */
5217 0x02, 0x03, 0x04, 0x05
5218};
5219
Kailang Yangdf694da2005-12-05 19:42:22 +01005220/* identical with ALC880 */
5221#define alc882_adc_nids alc880_adc_nids
5222#define alc882_adc_nids_alt alc880_adc_nids_alt
Linus Torvalds1da177e2005-04-16 15:20:36 -07005223
Takashi Iwaie1406342008-02-11 18:32:32 +01005224static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
5225static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
5226
Linus Torvalds1da177e2005-04-16 15:20:36 -07005227/* input MUX */
5228/* FIXME: should be a matrix-type input source selection */
5229
5230static struct hda_input_mux alc882_capture_source = {
5231 .num_items = 4,
5232 .items = {
5233 { "Mic", 0x0 },
5234 { "Front Mic", 0x1 },
5235 { "Line", 0x2 },
5236 { "CD", 0x4 },
5237 },
5238};
Linus Torvalds1da177e2005-04-16 15:20:36 -07005239#define alc882_mux_enum_info alc_mux_enum_info
5240#define alc882_mux_enum_get alc_mux_enum_get
5241
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005242static int alc882_mux_enum_put(struct snd_kcontrol *kcontrol,
5243 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005244{
5245 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
5246 struct alc_spec *spec = codec->spec;
5247 const struct hda_input_mux *imux = spec->input_mux;
5248 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwaie1406342008-02-11 18:32:32 +01005249 hda_nid_t nid = spec->capsrc_nids[adc_idx];
Linus Torvalds1da177e2005-04-16 15:20:36 -07005250 unsigned int *cur_val = &spec->cur_mux[adc_idx];
5251 unsigned int i, idx;
5252
5253 idx = ucontrol->value.enumerated.item[0];
5254 if (idx >= imux->num_items)
5255 idx = imux->num_items - 1;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005256 if (*cur_val == idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005257 return 0;
5258 for (i = 0; i < imux->num_items; i++) {
Takashi Iwai47fd8302007-08-10 17:11:07 +02005259 unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
5260 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005261 imux->items[i].index,
Takashi Iwai47fd8302007-08-10 17:11:07 +02005262 HDA_AMP_MUTE, v);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005263 }
5264 *cur_val = idx;
5265 return 1;
5266}
5267
Kailang Yangdf694da2005-12-05 19:42:22 +01005268/*
Kailang Yang272a5272007-05-14 11:00:38 +02005269 * 2ch mode
5270 */
5271static struct hda_verb alc882_3ST_ch2_init[] = {
5272 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
5273 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
5274 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
5275 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
5276 { } /* end */
5277};
5278
5279/*
5280 * 6ch mode
5281 */
5282static struct hda_verb alc882_3ST_ch6_init[] = {
5283 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5284 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
5285 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
5286 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5287 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
5288 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
5289 { } /* end */
5290};
5291
5292static struct hda_channel_mode alc882_3ST_6ch_modes[2] = {
5293 { 2, alc882_3ST_ch2_init },
5294 { 6, alc882_3ST_ch6_init },
5295};
5296
5297/*
Kailang Yangdf694da2005-12-05 19:42:22 +01005298 * 6ch mode
5299 */
5300static struct hda_verb alc882_sixstack_ch6_init[] = {
5301 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
5302 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5303 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5304 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5305 { } /* end */
5306};
5307
5308/*
5309 * 8ch mode
5310 */
5311static struct hda_verb alc882_sixstack_ch8_init[] = {
5312 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5313 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5314 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5315 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5316 { } /* end */
5317};
5318
5319static struct hda_channel_mode alc882_sixstack_modes[2] = {
5320 { 6, alc882_sixstack_ch6_init },
5321 { 8, alc882_sixstack_ch8_init },
5322};
5323
Takashi Iwai87350ad2007-08-16 18:19:38 +02005324/*
5325 * macbook pro ALC885 can switch LineIn to LineOut without loosing Mic
5326 */
5327
5328/*
5329 * 2ch mode
5330 */
5331static struct hda_verb alc885_mbp_ch2_init[] = {
5332 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
5333 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5334 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5335 { } /* end */
5336};
5337
5338/*
5339 * 6ch mode
5340 */
5341static struct hda_verb alc885_mbp_ch6_init[] = {
5342 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5343 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5344 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
5345 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5346 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5347 { } /* end */
5348};
5349
5350static struct hda_channel_mode alc885_mbp_6ch_modes[2] = {
5351 { 2, alc885_mbp_ch2_init },
5352 { 6, alc885_mbp_ch6_init },
5353};
5354
5355
Linus Torvalds1da177e2005-04-16 15:20:36 -07005356/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
5357 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
5358 */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01005359static struct snd_kcontrol_new alc882_base_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02005360 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005361 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005362 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005363 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005364 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
5365 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005366 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
5367 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005368 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005369 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005370 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
5371 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5372 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5373 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5374 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5375 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01005376 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005377 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5378 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01005379 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005380 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
5381 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5382 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005383 { } /* end */
5384};
5385
Takashi Iwai87350ad2007-08-16 18:19:38 +02005386static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01005387 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
5388 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
5389 HDA_CODEC_MUTE ("Speaker Playback Switch", 0x14, 0x00, HDA_OUTPUT),
5390 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
5391 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5392 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02005393 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
5394 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01005395 HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02005396 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
5397 { } /* end */
5398};
Kailang Yangbdd148a2007-05-08 15:19:08 +02005399static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
5400 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5401 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5402 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5403 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5404 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5405 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5406 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5407 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
5408 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5409 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5410 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
5411 { } /* end */
5412};
5413
Kailang Yang272a5272007-05-14 11:00:38 +02005414static struct snd_kcontrol_new alc882_targa_mixer[] = {
5415 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5416 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5417 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
5418 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5419 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5420 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5421 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5422 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5423 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc2007-09-07 10:57:44 +02005424 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005425 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
5426 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai96fe7cc2007-09-07 10:57:44 +02005427 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005428 { } /* end */
5429};
5430
5431/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
5432 * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
5433 */
5434static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
5435 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5436 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
5437 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
5438 HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT),
5439 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5440 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5441 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5442 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5443 HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
5444 HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
5445 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5446 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc2007-09-07 10:57:44 +02005447 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005448 { } /* end */
5449};
5450
Takashi Iwai914759b2007-09-06 14:52:04 +02005451static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
5452 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5453 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5454 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
5455 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5456 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5457 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5458 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5459 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5460 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
5461 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5462 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5463 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
5464 { } /* end */
5465};
5466
Kailang Yangdf694da2005-12-05 19:42:22 +01005467static struct snd_kcontrol_new alc882_chmode_mixer[] = {
5468 {
5469 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5470 .name = "Channel Mode",
5471 .info = alc_ch_mode_info,
5472 .get = alc_ch_mode_get,
5473 .put = alc_ch_mode_put,
5474 },
5475 { } /* end */
5476};
5477
Linus Torvalds1da177e2005-04-16 15:20:36 -07005478static struct hda_verb alc882_init_verbs[] = {
5479 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005480 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5481 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5482 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005483 /* Rear mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005484 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5485 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5486 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005487 /* CLFE mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005488 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5489 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5490 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005491 /* Side mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005492 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5493 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5494 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005495
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005496 /* Front Pin: output 0 (0x0c) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005497 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005498 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005499 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005500 /* Rear Pin: output 1 (0x0d) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005501 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005502 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005503 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005504 /* CLFE Pin: output 2 (0x0e) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005505 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005506 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005507 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005508 /* Side Pin: output 3 (0x0f) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005509 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005510 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005511 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005512 /* Mic (rear) pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005513 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005514 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5515 /* Front Mic pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005516 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005517 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5518 /* Line In pin: input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005519 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005520 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5521 /* Line-2 In: Headphone output (output 0 - 0x0c) */
5522 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5523 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5524 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005525 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005526 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005527
5528 /* FIXME: use matrix-type input source selection */
5529 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
5530 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Takashi Iwai05acb862005-06-10 19:50:25 +02005531 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5532 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5533 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5534 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005535 /* Input mixer2 */
Takashi Iwai05acb862005-06-10 19:50:25 +02005536 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5537 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5538 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5539 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005540 /* Input mixer3 */
Takashi Iwai05acb862005-06-10 19:50:25 +02005541 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5542 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5543 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5544 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5545 /* ADC1: mute amp left and right */
5546 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005547 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02005548 /* ADC2: mute amp left and right */
5549 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005550 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02005551 /* ADC3: mute amp left and right */
5552 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005553 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005554
5555 { }
5556};
5557
Takashi Iwai4b146cb2006-07-28 14:42:36 +02005558static struct hda_verb alc882_eapd_verbs[] = {
5559 /* change to EAPD mode */
5560 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01005561 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005562 { }
Takashi Iwai4b146cb2006-07-28 14:42:36 +02005563};
5564
Tobin Davis9102cd12006-12-15 10:02:12 +01005565/* Mac Pro test */
5566static struct snd_kcontrol_new alc882_macpro_mixer[] = {
5567 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5568 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5569 HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
5570 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
5571 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
5572 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x02, HDA_INPUT),
5573 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x02, HDA_INPUT),
5574 { } /* end */
5575};
5576
5577static struct hda_verb alc882_macpro_init_verbs[] = {
5578 /* Front mixer: unmute input/output amp left and right (volume = 0) */
5579 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5580 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5581 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5582 /* Front Pin: output 0 (0x0c) */
5583 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5584 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5585 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
5586 /* Front Mic pin: input vref at 80% */
5587 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5588 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5589 /* Speaker: output */
5590 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5591 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5592 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
5593 /* Headphone output (output 0 - 0x0c) */
5594 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5595 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5596 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
5597
5598 /* FIXME: use matrix-type input source selection */
5599 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
5600 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
5601 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5602 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5603 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5604 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5605 /* Input mixer2 */
5606 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5607 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5608 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5609 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5610 /* Input mixer3 */
5611 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5612 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5613 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5614 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5615 /* ADC1: mute amp left and right */
5616 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5617 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
5618 /* ADC2: mute amp left and right */
5619 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5620 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
5621 /* ADC3: mute amp left and right */
5622 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5623 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
5624
5625 { }
5626};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005627
Takashi Iwai87350ad2007-08-16 18:19:38 +02005628/* Macbook Pro rev3 */
5629static struct hda_verb alc885_mbp3_init_verbs[] = {
5630 /* Front mixer: unmute input/output amp left and right (volume = 0) */
5631 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5632 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5633 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5634 /* Rear mixer */
5635 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5636 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5637 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5638 /* Front Pin: output 0 (0x0c) */
5639 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5640 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5641 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
5642 /* HP Pin: output 0 (0x0d) */
5643 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
5644 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5645 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
5646 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
5647 /* Mic (rear) pin: input vref at 80% */
5648 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5649 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5650 /* Front Mic pin: input vref at 80% */
5651 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5652 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5653 /* Line In pin: use output 1 when in LineOut mode */
5654 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
5655 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5656 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
5657
5658 /* FIXME: use matrix-type input source selection */
5659 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
5660 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
5661 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5662 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5663 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5664 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5665 /* Input mixer2 */
5666 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5667 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5668 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5669 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5670 /* Input mixer3 */
5671 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5672 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5673 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5674 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5675 /* ADC1: mute amp left and right */
5676 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5677 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
5678 /* ADC2: mute amp left and right */
5679 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5680 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
5681 /* ADC3: mute amp left and right */
5682 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5683 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
5684
5685 { }
5686};
5687
Nicola Fagnanic54728d2007-07-19 23:28:52 +02005688/* iMac 24 mixer. */
5689static struct snd_kcontrol_new alc885_imac24_mixer[] = {
5690 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
5691 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
5692 { } /* end */
5693};
5694
5695/* iMac 24 init verbs. */
5696static struct hda_verb alc885_imac24_init_verbs[] = {
5697 /* Internal speakers: output 0 (0x0c) */
5698 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5699 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5700 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
5701 /* Internal speakers: output 0 (0x0c) */
5702 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5703 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5704 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
5705 /* Headphone: output 0 (0x0c) */
5706 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5707 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5708 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
5709 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
5710 /* Front Mic: input vref at 80% */
5711 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5712 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5713 { }
5714};
5715
5716/* Toggle speaker-output according to the hp-jack state */
5717static void alc885_imac24_automute(struct hda_codec *codec)
5718{
5719 unsigned int present;
5720
5721 present = snd_hda_codec_read(codec, 0x14, 0,
5722 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02005723 snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0,
5724 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
5725 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
5726 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Nicola Fagnanic54728d2007-07-19 23:28:52 +02005727}
5728
5729/* Processes unsolicited events. */
5730static void alc885_imac24_unsol_event(struct hda_codec *codec,
5731 unsigned int res)
5732{
5733 /* Headphone insertion or removal. */
5734 if ((res >> 26) == ALC880_HP_EVENT)
5735 alc885_imac24_automute(codec);
5736}
5737
Takashi Iwai87350ad2007-08-16 18:19:38 +02005738static void alc885_mbp3_automute(struct hda_codec *codec)
5739{
5740 unsigned int present;
5741
5742 present = snd_hda_codec_read(codec, 0x15, 0,
5743 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
5744 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
5745 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
5746 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
5747 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
5748
5749}
5750static void alc885_mbp3_unsol_event(struct hda_codec *codec,
5751 unsigned int res)
5752{
5753 /* Headphone insertion or removal. */
5754 if ((res >> 26) == ALC880_HP_EVENT)
5755 alc885_mbp3_automute(codec);
5756}
5757
5758
Kailang Yang272a5272007-05-14 11:00:38 +02005759static struct hda_verb alc882_targa_verbs[] = {
5760 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5761 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5762
5763 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5764 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5765
5766 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
5767 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
5768 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
5769
5770 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
5771 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
5772 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
5773 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
5774 { } /* end */
5775};
5776
5777/* toggle speaker-output according to the hp-jack state */
5778static void alc882_targa_automute(struct hda_codec *codec)
5779{
5780 unsigned int present;
5781
5782 present = snd_hda_codec_read(codec, 0x14, 0,
5783 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02005784 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
5785 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005786 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
5787 present ? 1 : 3);
Kailang Yang272a5272007-05-14 11:00:38 +02005788}
5789
5790static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
5791{
5792 /* Looks like the unsol event is incompatible with the standard
5793 * definition. 4bit tag is placed at 26 bit!
5794 */
5795 if (((res >> 26) == ALC880_HP_EVENT)) {
5796 alc882_targa_automute(codec);
5797 }
5798}
5799
5800static struct hda_verb alc882_asus_a7j_verbs[] = {
5801 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5802 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5803
5804 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5805 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5806 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5807
5808 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
5809 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
5810 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
5811
5812 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
5813 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
5814 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
5815 { } /* end */
5816};
5817
Takashi Iwai914759b2007-09-06 14:52:04 +02005818static struct hda_verb alc882_asus_a7m_verbs[] = {
5819 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5820 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5821
5822 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5823 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5824 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5825
5826 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
5827 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
5828 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
5829
5830 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
5831 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
5832 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
5833 { } /* end */
5834};
5835
Tobin Davis9102cd12006-12-15 10:02:12 +01005836static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
5837{
5838 unsigned int gpiostate, gpiomask, gpiodir;
5839
5840 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
5841 AC_VERB_GET_GPIO_DATA, 0);
5842
5843 if (!muted)
5844 gpiostate |= (1 << pin);
5845 else
5846 gpiostate &= ~(1 << pin);
5847
5848 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
5849 AC_VERB_GET_GPIO_MASK, 0);
5850 gpiomask |= (1 << pin);
5851
5852 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
5853 AC_VERB_GET_GPIO_DIRECTION, 0);
5854 gpiodir |= (1 << pin);
5855
5856
5857 snd_hda_codec_write(codec, codec->afg, 0,
5858 AC_VERB_SET_GPIO_MASK, gpiomask);
5859 snd_hda_codec_write(codec, codec->afg, 0,
5860 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
5861
5862 msleep(1);
5863
5864 snd_hda_codec_write(codec, codec->afg, 0,
5865 AC_VERB_SET_GPIO_DATA, gpiostate);
5866}
5867
Takashi Iwai7debbe52007-08-16 15:01:03 +02005868/* set up GPIO at initialization */
5869static void alc885_macpro_init_hook(struct hda_codec *codec)
5870{
5871 alc882_gpio_mute(codec, 0, 0);
5872 alc882_gpio_mute(codec, 1, 0);
5873}
5874
5875/* set up GPIO and update auto-muting at initialization */
5876static void alc885_imac24_init_hook(struct hda_codec *codec)
5877{
5878 alc885_macpro_init_hook(codec);
5879 alc885_imac24_automute(codec);
5880}
5881
Kailang Yangdf694da2005-12-05 19:42:22 +01005882/*
5883 * generic initialization of ADC, input mixers and output mixers
5884 */
5885static struct hda_verb alc882_auto_init_verbs[] = {
5886 /*
5887 * Unmute ADC0-2 and set the default input to mic-in
5888 */
5889 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
5890 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5891 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
5892 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5893 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
5894 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5895
Takashi Iwaicb53c622007-08-10 17:21:45 +02005896 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01005897 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005898 * Note: PASD motherboards uses the Line In 2 as the input for
5899 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01005900 */
5901 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005902 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5903 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5904 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5905 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5906 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01005907
5908 /*
5909 * Set up output mixers (0x0c - 0x0f)
5910 */
5911 /* set vol=0 to output mixers */
5912 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5913 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5914 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5915 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5916 /* set up input amps for analog loopback */
5917 /* Amp Indices: DAC = 0, mixer = 1 */
5918 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5919 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5920 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5921 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5922 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5923 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5924 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5925 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5926 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5927 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5928
5929 /* FIXME: use matrix-type input source selection */
5930 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
5931 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
5932 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5933 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
5934 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
5935 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
5936 /* Input mixer2 */
5937 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5938 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
5939 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
5940 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
5941 /* Input mixer3 */
5942 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5943 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
5944 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
5945 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
5946
5947 { }
5948};
5949
5950/* capture mixer elements */
5951static struct snd_kcontrol_new alc882_capture_alt_mixer[] = {
5952 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
5953 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
5954 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
5955 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
5956 {
5957 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5958 /* The multiple "Capture Source" controls confuse alsamixer
5959 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01005960 */
5961 /* .name = "Capture Source", */
5962 .name = "Input Source",
5963 .count = 2,
5964 .info = alc882_mux_enum_info,
5965 .get = alc882_mux_enum_get,
5966 .put = alc882_mux_enum_put,
5967 },
5968 { } /* end */
5969};
5970
5971static struct snd_kcontrol_new alc882_capture_mixer[] = {
5972 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
5973 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
5974 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
5975 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
5976 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
5977 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
5978 {
5979 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5980 /* The multiple "Capture Source" controls confuse alsamixer
5981 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01005982 */
5983 /* .name = "Capture Source", */
5984 .name = "Input Source",
5985 .count = 3,
5986 .info = alc882_mux_enum_info,
5987 .get = alc882_mux_enum_get,
5988 .put = alc882_mux_enum_put,
5989 },
5990 { } /* end */
5991};
5992
Takashi Iwaicb53c622007-08-10 17:21:45 +02005993#ifdef CONFIG_SND_HDA_POWER_SAVE
5994#define alc882_loopbacks alc880_loopbacks
5995#endif
5996
Kailang Yangdf694da2005-12-05 19:42:22 +01005997/* pcm configuration: identiacal with ALC880 */
5998#define alc882_pcm_analog_playback alc880_pcm_analog_playback
5999#define alc882_pcm_analog_capture alc880_pcm_analog_capture
6000#define alc882_pcm_digital_playback alc880_pcm_digital_playback
6001#define alc882_pcm_digital_capture alc880_pcm_digital_capture
6002
6003/*
6004 * configuration and preset
6005 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006006static const char *alc882_models[ALC882_MODEL_LAST] = {
6007 [ALC882_3ST_DIG] = "3stack-dig",
6008 [ALC882_6ST_DIG] = "6stack-dig",
6009 [ALC882_ARIMA] = "arima",
Kailang Yangbdd148a2007-05-08 15:19:08 +02006010 [ALC882_W2JC] = "w2jc",
Takashi Iwai0438a002007-09-06 14:54:11 +02006011 [ALC882_TARGA] = "targa",
6012 [ALC882_ASUS_A7J] = "asus-a7j",
6013 [ALC882_ASUS_A7M] = "asus-a7m",
Tobin Davis9102cd12006-12-15 10:02:12 +01006014 [ALC885_MACPRO] = "macpro",
Takashi Iwai87350ad2007-08-16 18:19:38 +02006015 [ALC885_MBP3] = "mbp3",
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006016 [ALC885_IMAC24] = "imac24",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006017 [ALC882_AUTO] = "auto",
6018};
6019
6020static struct snd_pci_quirk alc882_cfg_tbl[] = {
6021 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
Kailang Yang272a5272007-05-14 11:00:38 +02006022 SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
Kailang Yangac8842a2007-09-20 12:51:39 +02006023 SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
Takashi Iwai914759b2007-09-06 14:52:04 +02006024 SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006025 SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
Claudio Matsuokac5d9f1c2007-07-19 23:18:32 +02006026 SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
Tobin Davis7b9470d2006-12-28 13:56:48 +01006027 SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006028 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
Jiang zhe44447042008-01-28 12:28:24 +01006029 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006030 SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
6031 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
6032 SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA),
Kailang Yangdf694da2005-12-05 19:42:22 +01006033 {}
6034};
6035
6036static struct alc_config_preset alc882_presets[] = {
6037 [ALC882_3ST_DIG] = {
6038 .mixers = { alc882_base_mixer },
6039 .init_verbs = { alc882_init_verbs },
6040 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6041 .dac_nids = alc882_dac_nids,
6042 .dig_out_nid = ALC882_DIGOUT_NID,
Kailang Yangdf694da2005-12-05 19:42:22 +01006043 .dig_in_nid = ALC882_DIGIN_NID,
6044 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6045 .channel_mode = alc882_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02006046 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01006047 .input_mux = &alc882_capture_source,
6048 },
6049 [ALC882_6ST_DIG] = {
6050 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
6051 .init_verbs = { alc882_init_verbs },
6052 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6053 .dac_nids = alc882_dac_nids,
6054 .dig_out_nid = ALC882_DIGOUT_NID,
Kailang Yangdf694da2005-12-05 19:42:22 +01006055 .dig_in_nid = ALC882_DIGIN_NID,
6056 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
6057 .channel_mode = alc882_sixstack_modes,
6058 .input_mux = &alc882_capture_source,
6059 },
Takashi Iwai4b146cb2006-07-28 14:42:36 +02006060 [ALC882_ARIMA] = {
6061 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
6062 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs },
6063 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6064 .dac_nids = alc882_dac_nids,
6065 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
6066 .channel_mode = alc882_sixstack_modes,
6067 .input_mux = &alc882_capture_source,
6068 },
Kailang Yangbdd148a2007-05-08 15:19:08 +02006069 [ALC882_W2JC] = {
6070 .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
6071 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
6072 alc880_gpio1_init_verbs },
6073 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6074 .dac_nids = alc882_dac_nids,
6075 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
6076 .channel_mode = alc880_threestack_modes,
6077 .need_dac_fix = 1,
6078 .input_mux = &alc882_capture_source,
6079 .dig_out_nid = ALC882_DIGOUT_NID,
6080 },
Takashi Iwai87350ad2007-08-16 18:19:38 +02006081 [ALC885_MBP3] = {
6082 .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
6083 .init_verbs = { alc885_mbp3_init_verbs,
6084 alc880_gpio1_init_verbs },
6085 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6086 .dac_nids = alc882_dac_nids,
6087 .channel_mode = alc885_mbp_6ch_modes,
6088 .num_channel_mode = ARRAY_SIZE(alc885_mbp_6ch_modes),
6089 .input_mux = &alc882_capture_source,
6090 .dig_out_nid = ALC882_DIGOUT_NID,
6091 .dig_in_nid = ALC882_DIGIN_NID,
6092 .unsol_event = alc885_mbp3_unsol_event,
6093 .init_hook = alc885_mbp3_automute,
6094 },
Tobin Davis9102cd12006-12-15 10:02:12 +01006095 [ALC885_MACPRO] = {
6096 .mixers = { alc882_macpro_mixer },
6097 .init_verbs = { alc882_macpro_init_verbs },
6098 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6099 .dac_nids = alc882_dac_nids,
6100 .dig_out_nid = ALC882_DIGOUT_NID,
6101 .dig_in_nid = ALC882_DIGIN_NID,
6102 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6103 .channel_mode = alc882_ch_modes,
6104 .input_mux = &alc882_capture_source,
Takashi Iwai7debbe52007-08-16 15:01:03 +02006105 .init_hook = alc885_macpro_init_hook,
Tobin Davis9102cd12006-12-15 10:02:12 +01006106 },
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006107 [ALC885_IMAC24] = {
6108 .mixers = { alc885_imac24_mixer },
6109 .init_verbs = { alc885_imac24_init_verbs },
6110 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6111 .dac_nids = alc882_dac_nids,
6112 .dig_out_nid = ALC882_DIGOUT_NID,
6113 .dig_in_nid = ALC882_DIGIN_NID,
6114 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6115 .channel_mode = alc882_ch_modes,
6116 .input_mux = &alc882_capture_source,
6117 .unsol_event = alc885_imac24_unsol_event,
Takashi Iwai7debbe52007-08-16 15:01:03 +02006118 .init_hook = alc885_imac24_init_hook,
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006119 },
Kailang Yang272a5272007-05-14 11:00:38 +02006120 [ALC882_TARGA] = {
6121 .mixers = { alc882_targa_mixer, alc882_chmode_mixer,
6122 alc882_capture_mixer },
6123 .init_verbs = { alc882_init_verbs, alc882_targa_verbs},
6124 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6125 .dac_nids = alc882_dac_nids,
6126 .dig_out_nid = ALC882_DIGOUT_NID,
6127 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
6128 .adc_nids = alc882_adc_nids,
Takashi Iwaie1406342008-02-11 18:32:32 +01006129 .capsrc_nids = alc882_capsrc_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02006130 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
6131 .channel_mode = alc882_3ST_6ch_modes,
6132 .need_dac_fix = 1,
6133 .input_mux = &alc882_capture_source,
6134 .unsol_event = alc882_targa_unsol_event,
6135 .init_hook = alc882_targa_automute,
6136 },
6137 [ALC882_ASUS_A7J] = {
6138 .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer,
6139 alc882_capture_mixer },
6140 .init_verbs = { alc882_init_verbs, alc882_asus_a7j_verbs},
6141 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6142 .dac_nids = alc882_dac_nids,
6143 .dig_out_nid = ALC882_DIGOUT_NID,
6144 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
6145 .adc_nids = alc882_adc_nids,
Takashi Iwaie1406342008-02-11 18:32:32 +01006146 .capsrc_nids = alc882_capsrc_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02006147 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
6148 .channel_mode = alc882_3ST_6ch_modes,
6149 .need_dac_fix = 1,
6150 .input_mux = &alc882_capture_source,
6151 },
Takashi Iwai914759b2007-09-06 14:52:04 +02006152 [ALC882_ASUS_A7M] = {
6153 .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
6154 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
6155 alc880_gpio1_init_verbs,
6156 alc882_asus_a7m_verbs },
6157 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6158 .dac_nids = alc882_dac_nids,
6159 .dig_out_nid = ALC882_DIGOUT_NID,
6160 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
6161 .channel_mode = alc880_threestack_modes,
6162 .need_dac_fix = 1,
6163 .input_mux = &alc882_capture_source,
6164 },
Kailang Yangdf694da2005-12-05 19:42:22 +01006165};
6166
6167
6168/*
Takashi Iwaif95474e2007-07-10 00:47:43 +02006169 * Pin config fixes
6170 */
6171enum {
6172 PINFIX_ABIT_AW9D_MAX
6173};
6174
6175static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
6176 { 0x15, 0x01080104 }, /* side */
6177 { 0x16, 0x01011012 }, /* rear */
6178 { 0x17, 0x01016011 }, /* clfe */
6179 { }
6180};
6181
6182static const struct alc_pincfg *alc882_pin_fixes[] = {
6183 [PINFIX_ABIT_AW9D_MAX] = alc882_abit_aw9d_pinfix,
6184};
6185
6186static struct snd_pci_quirk alc882_pinfix_tbl[] = {
6187 SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
6188 {}
6189};
6190
6191/*
Kailang Yangdf694da2005-12-05 19:42:22 +01006192 * BIOS auto configuration
6193 */
6194static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
6195 hda_nid_t nid, int pin_type,
6196 int dac_idx)
6197{
6198 /* set as output */
6199 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006200 int idx;
6201
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006202 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01006203 if (spec->multiout.dac_nids[dac_idx] == 0x25)
6204 idx = 4;
6205 else
6206 idx = spec->multiout.dac_nids[dac_idx] - 2;
Kailang Yangdf694da2005-12-05 19:42:22 +01006207 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
6208
6209}
6210
6211static void alc882_auto_init_multi_out(struct hda_codec *codec)
6212{
6213 struct alc_spec *spec = codec->spec;
6214 int i;
6215
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006216 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Kailang Yangdf694da2005-12-05 19:42:22 +01006217 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006218 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006219 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01006220 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006221 alc882_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006222 i);
Kailang Yangdf694da2005-12-05 19:42:22 +01006223 }
6224}
6225
6226static void alc882_auto_init_hp_out(struct hda_codec *codec)
6227{
6228 struct alc_spec *spec = codec->spec;
6229 hda_nid_t pin;
6230
Takashi Iwaieb06ed82006-09-20 17:10:27 +02006231 pin = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006232 if (pin) /* connect to front */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006233 /* use dac 0 */
6234 alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006235 pin = spec->autocfg.speaker_pins[0];
6236 if (pin)
6237 alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +01006238}
6239
6240#define alc882_is_input_pin(nid) alc880_is_input_pin(nid)
6241#define ALC882_PIN_CD_NID ALC880_PIN_CD_NID
6242
6243static void alc882_auto_init_analog_input(struct hda_codec *codec)
6244{
6245 struct alc_spec *spec = codec->spec;
6246 int i;
6247
6248 for (i = 0; i < AUTO_PIN_LAST; i++) {
6249 hda_nid_t nid = spec->autocfg.input_pins[i];
6250 if (alc882_is_input_pin(nid)) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006251 snd_hda_codec_write(codec, nid, 0,
6252 AC_VERB_SET_PIN_WIDGET_CONTROL,
6253 i <= AUTO_PIN_FRONT_MIC ?
6254 PIN_VREF80 : PIN_IN);
Kailang Yangdf694da2005-12-05 19:42:22 +01006255 if (nid != ALC882_PIN_CD_NID)
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006256 snd_hda_codec_write(codec, nid, 0,
6257 AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangdf694da2005-12-05 19:42:22 +01006258 AMP_OUT_MUTE);
6259 }
6260 }
6261}
6262
Takashi Iwai776e1842007-08-29 15:07:11 +02006263/* add mic boosts if needed */
6264static int alc_auto_add_mic_boost(struct hda_codec *codec)
6265{
6266 struct alc_spec *spec = codec->spec;
6267 int err;
6268 hda_nid_t nid;
6269
6270 nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
Takashi Iwaice22e032008-01-11 17:38:35 +01006271 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
Takashi Iwai776e1842007-08-29 15:07:11 +02006272 err = add_control(spec, ALC_CTL_WIDGET_VOL,
6273 "Mic Boost",
6274 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
6275 if (err < 0)
6276 return err;
6277 }
6278 nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
Takashi Iwaice22e032008-01-11 17:38:35 +01006279 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
Takashi Iwai776e1842007-08-29 15:07:11 +02006280 err = add_control(spec, ALC_CTL_WIDGET_VOL,
6281 "Front Mic Boost",
6282 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
6283 if (err < 0)
6284 return err;
6285 }
6286 return 0;
6287}
6288
Kailang Yangdf694da2005-12-05 19:42:22 +01006289/* almost identical with ALC880 parser... */
6290static int alc882_parse_auto_config(struct hda_codec *codec)
6291{
6292 struct alc_spec *spec = codec->spec;
6293 int err = alc880_parse_auto_config(codec);
6294
6295 if (err < 0)
6296 return err;
Takashi Iwai776e1842007-08-29 15:07:11 +02006297 else if (!err)
6298 return 0; /* no config found */
6299
6300 err = alc_auto_add_mic_boost(codec);
6301 if (err < 0)
6302 return err;
6303
6304 /* hack - override the init verbs */
6305 spec->init_verbs[0] = alc882_auto_init_verbs;
6306
6307 return 1; /* config found */
Kailang Yangdf694da2005-12-05 19:42:22 +01006308}
6309
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006310/* additional initialization for auto-configuration model */
6311static void alc882_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01006312{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006313 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006314 alc882_auto_init_multi_out(codec);
6315 alc882_auto_init_hp_out(codec);
6316 alc882_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006317 if (spec->unsol_event)
6318 alc_sku_automute(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01006319}
6320
Linus Torvalds1da177e2005-04-16 15:20:36 -07006321static int patch_alc882(struct hda_codec *codec)
6322{
6323 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006324 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006325
Takashi Iwaie560d8d2005-09-09 14:21:46 +02006326 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006327 if (spec == NULL)
6328 return -ENOMEM;
6329
Linus Torvalds1da177e2005-04-16 15:20:36 -07006330 codec->spec = spec;
6331
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006332 board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
6333 alc882_models,
6334 alc882_cfg_tbl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006335
Kailang Yangdf694da2005-12-05 19:42:22 +01006336 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
Tobin Davis081d17c2007-02-15 17:46:18 +01006337 /* Pick up systems that don't supply PCI SSID */
6338 switch (codec->subsystem_id) {
6339 case 0x106b0c00: /* Mac Pro */
6340 board_config = ALC885_MACPRO;
6341 break;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006342 case 0x106b1000: /* iMac 24 */
6343 board_config = ALC885_IMAC24;
6344 break;
Jiang zhe3d5fa2e2008-01-10 13:05:47 +01006345 case 0x106b00a1: /* Macbook */
Takashi Iwai87350ad2007-08-16 18:19:38 +02006346 case 0x106b2c00: /* Macbook Pro rev3 */
6347 board_config = ALC885_MBP3;
6348 break;
Tobin Davis081d17c2007-02-15 17:46:18 +01006349 default:
6350 printk(KERN_INFO "hda_codec: Unknown model for ALC882, "
6351 "trying auto-probe from BIOS...\n");
6352 board_config = ALC882_AUTO;
6353 }
Kailang Yangdf694da2005-12-05 19:42:22 +01006354 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006355
Takashi Iwaif95474e2007-07-10 00:47:43 +02006356 alc_fix_pincfg(codec, alc882_pinfix_tbl, alc882_pin_fixes);
6357
Kailang Yangdf694da2005-12-05 19:42:22 +01006358 if (board_config == ALC882_AUTO) {
6359 /* automatic parse from the BIOS config */
6360 err = alc882_parse_auto_config(codec);
6361 if (err < 0) {
6362 alc_free(codec);
6363 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006364 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006365 printk(KERN_INFO
6366 "hda_codec: Cannot set up configuration "
6367 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01006368 board_config = ALC882_3ST_DIG;
6369 }
6370 }
6371
6372 if (board_config != ALC882_AUTO)
6373 setup_preset(spec, &alc882_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006374
6375 spec->stream_name_analog = "ALC882 Analog";
Kailang Yangdf694da2005-12-05 19:42:22 +01006376 spec->stream_analog_playback = &alc882_pcm_analog_playback;
6377 spec->stream_analog_capture = &alc882_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01006378 /* FIXME: setup DAC5 */
6379 /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
6380 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006381
6382 spec->stream_name_digital = "ALC882 Digital";
Kailang Yangdf694da2005-12-05 19:42:22 +01006383 spec->stream_digital_playback = &alc882_pcm_digital_playback;
6384 spec->stream_digital_capture = &alc882_pcm_digital_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006385
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006386 if (!spec->adc_nids && spec->input_mux) {
Kailang Yangdf694da2005-12-05 19:42:22 +01006387 /* check whether NID 0x07 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +01006388 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006389 /* get type */
6390 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Kailang Yangdf694da2005-12-05 19:42:22 +01006391 if (wcap != AC_WID_AUD_IN) {
6392 spec->adc_nids = alc882_adc_nids_alt;
6393 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids_alt);
Takashi Iwaie1406342008-02-11 18:32:32 +01006394 spec->capsrc_nids = alc882_capsrc_nids_alt;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006395 spec->mixers[spec->num_mixers] =
6396 alc882_capture_alt_mixer;
Kailang Yangdf694da2005-12-05 19:42:22 +01006397 spec->num_mixers++;
6398 } else {
6399 spec->adc_nids = alc882_adc_nids;
6400 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids);
Takashi Iwaie1406342008-02-11 18:32:32 +01006401 spec->capsrc_nids = alc882_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +01006402 spec->mixers[spec->num_mixers] = alc882_capture_mixer;
6403 spec->num_mixers++;
6404 }
6405 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006406
Takashi Iwai2134ea42008-01-10 16:53:55 +01006407 spec->vmaster_nid = 0x0c;
6408
Linus Torvalds1da177e2005-04-16 15:20:36 -07006409 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01006410 if (board_config == ALC882_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006411 spec->init_hook = alc882_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02006412#ifdef CONFIG_SND_HDA_POWER_SAVE
6413 if (!spec->loopback.amplist)
6414 spec->loopback.amplist = alc882_loopbacks;
6415#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006416
6417 return 0;
6418}
6419
6420/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006421 * ALC883 support
6422 *
6423 * ALC883 is almost identical with ALC880 but has cleaner and more flexible
6424 * configuration. Each pin widget can choose any input DACs and a mixer.
6425 * Each ADC is connected from a mixer of all inputs. This makes possible
6426 * 6-channel independent captures.
6427 *
6428 * In addition, an independent DAC for the multi-playback (not used in this
6429 * driver yet).
6430 */
6431#define ALC883_DIGOUT_NID 0x06
6432#define ALC883_DIGIN_NID 0x0a
6433
6434static hda_nid_t alc883_dac_nids[4] = {
6435 /* front, rear, clfe, rear_surr */
6436 0x02, 0x04, 0x03, 0x05
6437};
6438
6439static hda_nid_t alc883_adc_nids[2] = {
6440 /* ADC1-2 */
6441 0x08, 0x09,
6442};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006443
Takashi Iwaie1406342008-02-11 18:32:32 +01006444static hda_nid_t alc883_capsrc_nids[2] = { 0x23, 0x22 };
6445
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006446/* input MUX */
6447/* FIXME: should be a matrix-type input source selection */
6448
6449static struct hda_input_mux alc883_capture_source = {
6450 .num_items = 4,
6451 .items = {
6452 { "Mic", 0x0 },
6453 { "Front Mic", 0x1 },
6454 { "Line", 0x2 },
6455 { "CD", 0x4 },
6456 },
6457};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006458
6459static struct hda_input_mux alc883_lenovo_101e_capture_source = {
6460 .num_items = 2,
6461 .items = {
6462 { "Mic", 0x1 },
6463 { "Line", 0x2 },
6464 },
6465};
6466
Kailang Yang272a5272007-05-14 11:00:38 +02006467static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
6468 .num_items = 4,
6469 .items = {
6470 { "Mic", 0x0 },
6471 { "iMic", 0x1 },
6472 { "Line", 0x2 },
6473 { "CD", 0x4 },
6474 },
6475};
6476
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006477#define alc883_mux_enum_info alc_mux_enum_info
6478#define alc883_mux_enum_get alc_mux_enum_get
Takashi Iwaie1406342008-02-11 18:32:32 +01006479/* ALC883 has the ALC882-type input selection */
6480#define alc883_mux_enum_put alc882_mux_enum_put
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006481
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006482/*
6483 * 2ch mode
6484 */
6485static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
6486 { 2, NULL }
6487};
6488
6489/*
6490 * 2ch mode
6491 */
6492static struct hda_verb alc883_3ST_ch2_init[] = {
6493 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6494 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6495 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
6496 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6497 { } /* end */
6498};
6499
6500/*
Tobin Davisb2011312007-09-17 12:45:11 +02006501 * 4ch mode
6502 */
6503static struct hda_verb alc883_3ST_ch4_init[] = {
6504 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6505 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6506 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6507 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6508 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6509 { } /* end */
6510};
6511
6512/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006513 * 6ch mode
6514 */
6515static struct hda_verb alc883_3ST_ch6_init[] = {
6516 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6517 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6518 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
6519 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6520 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6521 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6522 { } /* end */
6523};
6524
Tobin Davisb2011312007-09-17 12:45:11 +02006525static struct hda_channel_mode alc883_3ST_6ch_modes[3] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006526 { 2, alc883_3ST_ch2_init },
Tobin Davisb2011312007-09-17 12:45:11 +02006527 { 4, alc883_3ST_ch4_init },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006528 { 6, alc883_3ST_ch6_init },
6529};
6530
6531/*
6532 * 6ch mode
6533 */
6534static struct hda_verb alc883_sixstack_ch6_init[] = {
6535 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
6536 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6537 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6538 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6539 { } /* end */
6540};
6541
6542/*
6543 * 8ch mode
6544 */
6545static struct hda_verb alc883_sixstack_ch8_init[] = {
6546 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6547 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6548 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6549 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6550 { } /* end */
6551};
6552
6553static struct hda_channel_mode alc883_sixstack_modes[2] = {
6554 { 6, alc883_sixstack_ch6_init },
6555 { 8, alc883_sixstack_ch8_init },
6556};
6557
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01006558static struct hda_verb alc883_medion_eapd_verbs[] = {
6559 /* eanable EAPD on medion laptop */
6560 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
6561 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
6562 { }
6563};
6564
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006565/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
6566 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
6567 */
6568
6569static struct snd_kcontrol_new alc883_base_mixer[] = {
6570 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6571 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6572 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6573 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
6574 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6575 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
6576 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
6577 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
6578 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
6579 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
6580 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6581 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6582 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6583 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6584 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6585 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006586 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006587 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6588 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006589 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006590 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6591 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6592 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6593 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6594 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6595 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6596 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6597 {
6598 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6599 /* .name = "Capture Source", */
6600 .name = "Input Source",
6601 .count = 2,
6602 .info = alc883_mux_enum_info,
6603 .get = alc883_mux_enum_get,
6604 .put = alc883_mux_enum_put,
6605 },
6606 { } /* end */
6607};
6608
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01006609static struct snd_kcontrol_new alc883_mitac_mixer[] = {
6610 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6611 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6612 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6613 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
6614 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
6615 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
6616 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
6617 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6618 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6619 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6620 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6621 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
6622 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6623 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6624 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6625 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6626 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6627 {
6628 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6629 /* .name = "Capture Source", */
6630 .name = "Input Source",
6631 .count = 2,
6632 .info = alc883_mux_enum_info,
6633 .get = alc883_mux_enum_get,
6634 .put = alc883_mux_enum_put,
6635 },
6636 { } /* end */
6637};
6638
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006639static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
6640 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6641 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6642 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6643 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6644 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6645 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6646 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6647 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006648 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006649 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6650 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006651 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006652 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6653 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6654 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6655 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6656 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6657 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6658 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6659 {
6660 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6661 /* .name = "Capture Source", */
6662 .name = "Input Source",
6663 .count = 2,
6664 .info = alc883_mux_enum_info,
6665 .get = alc883_mux_enum_get,
6666 .put = alc883_mux_enum_put,
6667 },
6668 { } /* end */
6669};
6670
6671static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
6672 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6673 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6674 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6675 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
6676 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6677 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
6678 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
6679 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
6680 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6681 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6682 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6683 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6684 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6685 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006686 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006687 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6688 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006689 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006690 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6691 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6692 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6693 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6694 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6695 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6696 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6697 {
6698 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6699 /* .name = "Capture Source", */
6700 .name = "Input Source",
6701 .count = 2,
6702 .info = alc883_mux_enum_info,
6703 .get = alc883_mux_enum_get,
6704 .put = alc883_mux_enum_put,
6705 },
6706 { } /* end */
6707};
6708
Takashi Iwaid1d985f2006-11-23 19:27:12 +01006709static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
Tobin Davisc07584c2006-10-13 12:32:16 +02006710 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6711 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
6712 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6713 HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
6714 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6715 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
6716 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT),
6717 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
6718 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6719 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6720 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6721 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6722 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6723 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006724 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02006725 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6726 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006727 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02006728 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6729 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6730 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6731 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6732 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6733
6734 {
6735 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6736 /* .name = "Capture Source", */
6737 .name = "Input Source",
6738 .count = 1,
6739 .info = alc883_mux_enum_info,
6740 .get = alc883_mux_enum_get,
6741 .put = alc883_mux_enum_put,
6742 },
6743 { } /* end */
6744};
6745
Kailang Yangccc656c2006-10-17 12:32:26 +02006746static struct snd_kcontrol_new alc883_tagra_mixer[] = {
6747 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6748 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
6749 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6750 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6751 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
6752 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6753 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
6754 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
6755 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
6756 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6757 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6758 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6759 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6760 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006761 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02006762 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6763 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6764 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6765 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6766 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6767 {
6768 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6769 /* .name = "Capture Source", */
6770 .name = "Input Source",
6771 .count = 2,
6772 .info = alc883_mux_enum_info,
6773 .get = alc883_mux_enum_get,
6774 .put = alc883_mux_enum_put,
6775 },
6776 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006777};
Kailang Yangccc656c2006-10-17 12:32:26 +02006778
6779static struct snd_kcontrol_new alc883_tagra_2ch_mixer[] = {
6780 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6781 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
6782 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6783 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6784 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6785 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006786 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02006787 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6788 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6789 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6790 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6791 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6792 {
6793 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6794 /* .name = "Capture Source", */
6795 .name = "Input Source",
6796 .count = 2,
6797 .info = alc883_mux_enum_info,
6798 .get = alc883_mux_enum_get,
6799 .put = alc883_mux_enum_put,
6800 },
6801 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006802};
Kailang Yangccc656c2006-10-17 12:32:26 +02006803
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006804static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
6805 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6806 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01006807 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6808 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006809 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6810 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6811 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6812 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6813 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6814 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6815 {
6816 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6817 /* .name = "Capture Source", */
6818 .name = "Input Source",
6819 .count = 1,
6820 .info = alc883_mux_enum_info,
6821 .get = alc883_mux_enum_get,
6822 .put = alc883_mux_enum_put,
6823 },
6824 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006825};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006826
Kailang Yang272a5272007-05-14 11:00:38 +02006827static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
6828 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6829 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
6830 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
6831 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6832 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6833 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6834 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6835 HDA_CODEC_VOLUME("iMic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6836 HDA_CODEC_MUTE("iMic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6837 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6838 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6839 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6840 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6841 {
6842 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6843 /* .name = "Capture Source", */
6844 .name = "Input Source",
6845 .count = 2,
6846 .info = alc883_mux_enum_info,
6847 .get = alc883_mux_enum_get,
6848 .put = alc883_mux_enum_put,
6849 },
6850 { } /* end */
6851};
6852
6853static struct snd_kcontrol_new alc883_medion_md2_mixer[] = {
6854 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6855 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
6856 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
6857 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6858 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6859 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6860 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6861 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6862 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6863 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6864 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6865 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6866 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6867 {
6868 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6869 /* .name = "Capture Source", */
6870 .name = "Input Source",
6871 .count = 2,
6872 .info = alc883_mux_enum_info,
6873 .get = alc883_mux_enum_get,
6874 .put = alc883_mux_enum_put,
6875 },
6876 { } /* end */
6877};
6878
Claudio Matsuoka4723c022007-07-13 14:36:19 +02006879static struct snd_kcontrol_new alc888_6st_hp_mixer[] = {
Claudio Matsuokacd1e3b42007-07-06 12:10:01 +02006880 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6881 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6882 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
6883 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
6884 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
6885 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
6886 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
6887 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
6888 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
6889 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
6890 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6891 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6892 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6893 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6894 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6895 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6896 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6897 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6898 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6899 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
6900 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6901 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6902 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6903 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6904 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6905 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6906 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6907 {
6908 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6909 /* .name = "Capture Source", */
6910 .name = "Input Source",
6911 .count = 2,
6912 .info = alc883_mux_enum_info,
6913 .get = alc883_mux_enum_get,
6914 .put = alc883_mux_enum_put,
6915 },
6916 { } /* end */
6917};
6918
Claudio Matsuoka4723c022007-07-13 14:36:19 +02006919static struct snd_kcontrol_new alc888_3st_hp_mixer[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02006920 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6921 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6922 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
6923 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
6924 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
6925 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
6926 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
6927 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
6928 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6929 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6930 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6931 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6932 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6933 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6934 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6935 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6936 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6937 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
6938 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6939 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6940 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6941 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6942 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6943 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6944 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6945 {
6946 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6947 /* .name = "Capture Source", */
6948 .name = "Input Source",
6949 .count = 2,
6950 .info = alc883_mux_enum_info,
6951 .get = alc883_mux_enum_get,
6952 .put = alc883_mux_enum_put,
6953 },
6954 { } /* end */
6955};
6956
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01006957static struct snd_kcontrol_new alc888_6st_dell_mixer[] = {
6958 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6959 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6960 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
6961 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
6962 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
6963 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
6964 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
6965 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
6966 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
6967 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
6968 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6969 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6970 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6971 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6972 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6973 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6974 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6975 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6976 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6977 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
6978 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6979 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6980 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6981 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6982 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6983 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6984 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6985 {
6986 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6987 /* .name = "Capture Source", */
6988 .name = "Input Source",
6989 .count = 2,
6990 .info = alc883_mux_enum_info,
6991 .get = alc883_mux_enum_get,
6992 .put = alc883_mux_enum_put,
6993 },
6994 { } /* end */
6995};
6996
Tobin Davis2880a862007-08-07 11:50:26 +02006997static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02006998 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6999 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007000 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007001 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7002 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02007003 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7004 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7005 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007006 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7007 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7008 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7009 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7010 {
7011 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7012 /* .name = "Capture Source", */
7013 .name = "Input Source",
7014 .count = 2,
7015 .info = alc883_mux_enum_info,
7016 .get = alc883_mux_enum_get,
7017 .put = alc883_mux_enum_put,
7018 },
7019 { } /* end */
Kailang Yangd1a991a2007-08-15 16:21:59 +02007020};
Tobin Davis2880a862007-08-07 11:50:26 +02007021
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007022static struct snd_kcontrol_new alc883_chmode_mixer[] = {
7023 {
7024 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7025 .name = "Channel Mode",
7026 .info = alc_ch_mode_info,
7027 .get = alc_ch_mode_get,
7028 .put = alc_ch_mode_put,
7029 },
7030 { } /* end */
7031};
7032
7033static struct hda_verb alc883_init_verbs[] = {
7034 /* ADC1: mute amp left and right */
7035 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7036 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7037 /* ADC2: mute amp left and right */
7038 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7039 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
7040 /* Front mixer: unmute input/output amp left and right (volume = 0) */
7041 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7042 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7043 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7044 /* Rear mixer */
7045 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7046 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7047 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7048 /* CLFE mixer */
7049 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7050 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7051 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7052 /* Side mixer */
7053 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7054 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7055 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7056
Takashi Iwaicb53c622007-08-10 17:21:45 +02007057 /* mute analog input loopbacks */
7058 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7059 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7060 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7061 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7062 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007063
7064 /* Front Pin: output 0 (0x0c) */
7065 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7066 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7067 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7068 /* Rear Pin: output 1 (0x0d) */
7069 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7070 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7071 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
7072 /* CLFE Pin: output 2 (0x0e) */
7073 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7074 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7075 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
7076 /* Side Pin: output 3 (0x0f) */
7077 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7078 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7079 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
7080 /* Mic (rear) pin: input vref at 80% */
7081 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7082 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7083 /* Front Mic pin: input vref at 80% */
7084 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7085 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7086 /* Line In pin: input */
7087 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7088 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7089 /* Line-2 In: Headphone output (output 0 - 0x0c) */
7090 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7091 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7092 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
7093 /* CD pin widget for input */
7094 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7095
7096 /* FIXME: use matrix-type input source selection */
7097 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
7098 /* Input mixer2 */
7099 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7100 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7101 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
7102 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
7103 /* Input mixer3 */
7104 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7105 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7106 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
7107 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
7108 { }
7109};
7110
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007111/* toggle speaker-output according to the hp-jack state */
7112static void alc883_mitac_hp_automute(struct hda_codec *codec)
7113{
7114 unsigned int present;
7115
7116 present = snd_hda_codec_read(codec, 0x15, 0,
7117 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7118 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7119 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7120 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
7121 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7122}
7123
7124/* auto-toggle front mic */
7125/*
7126static void alc883_mitac_mic_automute(struct hda_codec *codec)
7127{
7128 unsigned int present;
7129 unsigned char bits;
7130
7131 present = snd_hda_codec_read(codec, 0x18, 0,
7132 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7133 bits = present ? HDA_AMP_MUTE : 0;
7134 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
7135}
7136*/
7137
7138static void alc883_mitac_automute(struct hda_codec *codec)
7139{
7140 alc883_mitac_hp_automute(codec);
7141 /* alc883_mitac_mic_automute(codec); */
7142}
7143
7144static void alc883_mitac_unsol_event(struct hda_codec *codec,
7145 unsigned int res)
7146{
7147 switch (res >> 26) {
7148 case ALC880_HP_EVENT:
7149 alc883_mitac_hp_automute(codec);
7150 break;
7151 case ALC880_MIC_EVENT:
7152 /* alc883_mitac_mic_automute(codec); */
7153 break;
7154 }
7155}
7156
7157static struct hda_verb alc883_mitac_verbs[] = {
7158 /* HP */
7159 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7160 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7161 /* Subwoofer */
7162 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
7163 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7164
7165 /* enable unsolicited event */
7166 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7167 /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
7168
7169 { } /* end */
7170};
7171
Kailang Yangccc656c2006-10-17 12:32:26 +02007172static struct hda_verb alc883_tagra_verbs[] = {
7173 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7174 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7175
7176 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7177 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7178
7179 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
7180 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
7181 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
7182
7183 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007184 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
7185 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
7186 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
Kailang Yangccc656c2006-10-17 12:32:26 +02007187
7188 { } /* end */
7189};
7190
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007191static struct hda_verb alc883_lenovo_101e_verbs[] = {
7192 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7193 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
7194 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
7195 { } /* end */
7196};
7197
Kailang Yang272a5272007-05-14 11:00:38 +02007198static struct hda_verb alc883_lenovo_nb0763_verbs[] = {
7199 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7200 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7201 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7202 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7203 { } /* end */
7204};
7205
7206static struct hda_verb alc888_lenovo_ms7195_verbs[] = {
7207 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7208 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7209 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7210 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN},
7211 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7212 { } /* end */
7213};
7214
Kailang Yang189609a2007-08-20 11:31:23 +02007215static struct hda_verb alc883_haier_w66_verbs[] = {
7216 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7217 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7218
7219 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7220
7221 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
7222 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7223 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7224 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7225 { } /* end */
7226};
7227
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007228static struct hda_verb alc888_6st_hp_verbs[] = {
Claudio Matsuokacd1e3b42007-07-06 12:10:01 +02007229 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
7230 {0x15, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Rear : output 2 (0x0e) */
7231 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* CLFE : output 1 (0x0d) */
7232 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, /* Side : output 3 (0x0f) */
7233 { }
7234};
7235
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007236static struct hda_verb alc888_3st_hp_verbs[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007237 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
7238 {0x18, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */
7239 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */
7240 { }
7241};
7242
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007243static struct hda_verb alc888_6st_dell_verbs[] = {
7244 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
7245 {0x15, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Rear : output 1 (0x0e) */
7246 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* CLFE : output 2 (0x0d) */
7247 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, /* Side : output 3 (0x0f) */
7248 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7249 { }
7250};
7251
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007252static struct hda_verb alc888_3st_hp_2ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007253 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7254 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7255 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7256 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7257 { }
7258};
7259
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007260static struct hda_verb alc888_3st_hp_6ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007261 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7262 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7263 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7264 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7265 { }
7266};
7267
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007268static struct hda_channel_mode alc888_3st_hp_modes[2] = {
7269 { 2, alc888_3st_hp_2ch_init },
7270 { 6, alc888_3st_hp_6ch_init },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007271};
7272
Kailang Yang272a5272007-05-14 11:00:38 +02007273/* toggle front-jack and RCA according to the hp-jack state */
7274static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
7275{
7276 unsigned int present;
7277
7278 present = snd_hda_codec_read(codec, 0x1b, 0,
7279 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007280 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7281 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7282 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7283 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007284}
7285
7286/* toggle RCA according to the front-jack state */
7287static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec)
7288{
7289 unsigned int present;
7290
7291 present = snd_hda_codec_read(codec, 0x14, 0,
7292 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007293 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7294 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007295}
Takashi Iwai47fd8302007-08-10 17:11:07 +02007296
Kailang Yang272a5272007-05-14 11:00:38 +02007297static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec,
7298 unsigned int res)
7299{
7300 if ((res >> 26) == ALC880_HP_EVENT)
7301 alc888_lenovo_ms7195_front_automute(codec);
7302 if ((res >> 26) == ALC880_FRONT_EVENT)
7303 alc888_lenovo_ms7195_rca_automute(codec);
7304}
7305
7306static struct hda_verb alc883_medion_md2_verbs[] = {
7307 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7308 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7309
7310 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7311
7312 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7313 { } /* end */
7314};
7315
7316/* toggle speaker-output according to the hp-jack state */
7317static void alc883_medion_md2_automute(struct hda_codec *codec)
7318{
7319 unsigned int present;
7320
7321 present = snd_hda_codec_read(codec, 0x14, 0,
7322 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007323 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7324 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007325}
7326
7327static void alc883_medion_md2_unsol_event(struct hda_codec *codec,
7328 unsigned int res)
7329{
7330 if ((res >> 26) == ALC880_HP_EVENT)
7331 alc883_medion_md2_automute(codec);
7332}
7333
Kailang Yangccc656c2006-10-17 12:32:26 +02007334/* toggle speaker-output according to the hp-jack state */
7335static void alc883_tagra_automute(struct hda_codec *codec)
7336{
7337 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007338 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02007339
7340 present = snd_hda_codec_read(codec, 0x14, 0,
7341 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007342 bits = present ? HDA_AMP_MUTE : 0;
7343 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
7344 HDA_AMP_MUTE, bits);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02007345 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
7346 present ? 1 : 3);
Kailang Yangccc656c2006-10-17 12:32:26 +02007347}
7348
7349static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res)
7350{
7351 if ((res >> 26) == ALC880_HP_EVENT)
7352 alc883_tagra_automute(codec);
7353}
7354
Kailang Yang189609a2007-08-20 11:31:23 +02007355static void alc883_haier_w66_automute(struct hda_codec *codec)
7356{
7357 unsigned int present;
7358 unsigned char bits;
7359
7360 present = snd_hda_codec_read(codec, 0x1b, 0,
7361 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7362 bits = present ? 0x80 : 0;
7363 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7364 0x80, bits);
7365}
7366
7367static void alc883_haier_w66_unsol_event(struct hda_codec *codec,
7368 unsigned int res)
7369{
7370 if ((res >> 26) == ALC880_HP_EVENT)
7371 alc883_haier_w66_automute(codec);
7372}
7373
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007374static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
7375{
7376 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007377 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007378
7379 present = snd_hda_codec_read(codec, 0x14, 0,
7380 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007381 bits = present ? HDA_AMP_MUTE : 0;
7382 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7383 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007384}
7385
7386static void alc883_lenovo_101e_all_automute(struct hda_codec *codec)
7387{
7388 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007389 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007390
7391 present = snd_hda_codec_read(codec, 0x1b, 0,
7392 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007393 bits = present ? HDA_AMP_MUTE : 0;
7394 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7395 HDA_AMP_MUTE, bits);
7396 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7397 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007398}
7399
7400static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec,
7401 unsigned int res)
7402{
7403 if ((res >> 26) == ALC880_HP_EVENT)
7404 alc883_lenovo_101e_all_automute(codec);
7405 if ((res >> 26) == ALC880_FRONT_EVENT)
7406 alc883_lenovo_101e_ispeaker_automute(codec);
7407}
7408
Takashi Iwai676a9b52007-08-16 15:23:35 +02007409/* toggle speaker-output according to the hp-jack state */
7410static void alc883_acer_aspire_automute(struct hda_codec *codec)
7411{
7412 unsigned int present;
7413
7414 present = snd_hda_codec_read(codec, 0x14, 0,
7415 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7416 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7417 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7418 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
7419 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7420}
7421
7422static void alc883_acer_aspire_unsol_event(struct hda_codec *codec,
7423 unsigned int res)
7424{
7425 if ((res >> 26) == ALC880_HP_EVENT)
7426 alc883_acer_aspire_automute(codec);
7427}
7428
Kailang Yangd1a991a2007-08-15 16:21:59 +02007429static struct hda_verb alc883_acer_eapd_verbs[] = {
7430 /* HP Pin: output 0 (0x0c) */
7431 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7432 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7433 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7434 /* Front Pin: output 0 (0x0c) */
Takashi Iwai676a9b52007-08-16 15:23:35 +02007435 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7436 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangd1a991a2007-08-15 16:21:59 +02007437 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangd1a991a2007-08-15 16:21:59 +02007438 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
7439 /* eanable EAPD on medion laptop */
7440 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
7441 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
Takashi Iwai676a9b52007-08-16 15:23:35 +02007442 /* enable unsolicited event */
7443 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangd1a991a2007-08-15 16:21:59 +02007444 { }
7445};
7446
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007447static void alc888_6st_dell_front_automute(struct hda_codec *codec)
7448{
7449 unsigned int present;
7450
7451 present = snd_hda_codec_read(codec, 0x1b, 0,
7452 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7453 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7454 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7455 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7456 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7457 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
7458 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7459 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
7460 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7461}
7462
7463static void alc888_6st_dell_unsol_event(struct hda_codec *codec,
7464 unsigned int res)
7465{
7466 switch (res >> 26) {
7467 case ALC880_HP_EVENT:
7468 printk("hp_event\n");
7469 alc888_6st_dell_front_automute(codec);
7470 break;
7471 }
7472}
7473
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007474/*
7475 * generic initialization of ADC, input mixers and output mixers
7476 */
7477static struct hda_verb alc883_auto_init_verbs[] = {
7478 /*
7479 * Unmute ADC0-2 and set the default input to mic-in
7480 */
7481 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7482 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7483 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
7484 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7485
Takashi Iwaicb53c622007-08-10 17:21:45 +02007486 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007487 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007488 * Note: PASD motherboards uses the Line In 2 as the input for
7489 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007490 */
7491 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02007492 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7493 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7494 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7495 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7496 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007497
7498 /*
7499 * Set up output mixers (0x0c - 0x0f)
7500 */
7501 /* set vol=0 to output mixers */
7502 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7503 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7504 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7505 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7506 /* set up input amps for analog loopback */
7507 /* Amp Indices: DAC = 0, mixer = 1 */
7508 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7509 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7510 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7511 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7512 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7513 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7514 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7515 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7516 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7517 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7518
7519 /* FIXME: use matrix-type input source selection */
7520 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
7521 /* Input mixer1 */
7522 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7523 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7524 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007525 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007526 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
7527 /* Input mixer2 */
7528 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7529 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7530 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007531 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
Andy Shevchenkoe3cde642007-12-03 16:50:58 +01007532 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007533
7534 { }
7535};
7536
7537/* capture mixer elements */
7538static struct snd_kcontrol_new alc883_capture_mixer[] = {
7539 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7540 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7541 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7542 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7543 {
7544 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7545 /* The multiple "Capture Source" controls confuse alsamixer
7546 * So call somewhat different..
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007547 */
7548 /* .name = "Capture Source", */
7549 .name = "Input Source",
7550 .count = 2,
7551 .info = alc882_mux_enum_info,
7552 .get = alc882_mux_enum_get,
7553 .put = alc882_mux_enum_put,
7554 },
7555 { } /* end */
7556};
7557
Takashi Iwaicb53c622007-08-10 17:21:45 +02007558#ifdef CONFIG_SND_HDA_POWER_SAVE
7559#define alc883_loopbacks alc880_loopbacks
7560#endif
7561
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007562/* pcm configuration: identiacal with ALC880 */
7563#define alc883_pcm_analog_playback alc880_pcm_analog_playback
7564#define alc883_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +01007565#define alc883_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007566#define alc883_pcm_digital_playback alc880_pcm_digital_playback
7567#define alc883_pcm_digital_capture alc880_pcm_digital_capture
7568
7569/*
7570 * configuration and preset
7571 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007572static const char *alc883_models[ALC883_MODEL_LAST] = {
7573 [ALC883_3ST_2ch_DIG] = "3stack-dig",
7574 [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
7575 [ALC883_3ST_6ch] = "3stack-6ch",
7576 [ALC883_6ST_DIG] = "6stack-dig",
7577 [ALC883_TARGA_DIG] = "targa-dig",
7578 [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007579 [ALC883_ACER] = "acer",
Tobin Davis2880a862007-08-07 11:50:26 +02007580 [ALC883_ACER_ASPIRE] = "acer-aspire",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007581 [ALC883_MEDION] = "medion",
Kailang Yang272a5272007-05-14 11:00:38 +02007582 [ALC883_MEDION_MD2] = "medion-md2",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007583 [ALC883_LAPTOP_EAPD] = "laptop-eapd",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007584 [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
Kailang Yang272a5272007-05-14 11:00:38 +02007585 [ALC883_LENOVO_NB0763] = "lenovo-nb0763",
7586 [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
Kailang Yang189609a2007-08-20 11:31:23 +02007587 [ALC883_HAIER_W66] = "haier-w66",
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007588 [ALC888_6ST_HP] = "6stack-hp",
7589 [ALC888_3ST_HP] = "3stack-hp",
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007590 [ALC888_6ST_DELL] = "6stack-dell",
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007591 [ALC883_MITAC] = "mitac",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007592 [ALC883_AUTO] = "auto",
7593};
7594
7595static struct snd_pci_quirk alc883_cfg_tbl[] = {
7596 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007597 SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
7598 SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
7599 SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
7600 SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), /* default Acer */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007601 SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
Tobin Davisfebe3372007-06-12 11:27:46 +02007602 SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007603 SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
7604 SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
7605 SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC888_6ST_HP),
7606 SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007607 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007608 SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
7609 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
7610 SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
Tobin Davis57b14f22007-04-18 23:05:36 +02007611 SND_PCI_QUIRK(0x1458, 0xa002, "MSI", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007612 SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
7613 SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
7614 SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
7615 SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
7616 SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
7617 SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
7618 SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
7619 SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
7620 SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
7621 SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
7622 SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
7623 SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
7624 SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007625 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
7626 SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
Tobin Davis799f88a2007-05-29 14:29:08 +02007627 SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
Leonard Norrgard2a296cb2007-01-08 11:28:22 +01007628 SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
Tobin Davis2dcd5222007-07-10 17:04:57 +02007629 SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007630 SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007631 SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
7632 SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD),
Daniel T Chene60623b2007-05-29 03:41:55 -04007633 SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007634 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
Kailang Yang272a5272007-05-14 11:00:38 +02007635 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
Kailang Yang272a5272007-05-14 11:00:38 +02007636 SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007637 SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
7638 SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Kailang Yang272a5272007-05-14 11:00:38 +02007639 SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
Andrew Paprocki0b167bf2008-02-03 10:15:44 +01007640 SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
Kailang Yang189609a2007-08-20 11:31:23 +02007641 SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007642 SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007643 {}
7644};
7645
7646static struct alc_config_preset alc883_presets[] = {
7647 [ALC883_3ST_2ch_DIG] = {
7648 .mixers = { alc883_3ST_2ch_mixer },
7649 .init_verbs = { alc883_init_verbs },
7650 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7651 .dac_nids = alc883_dac_nids,
7652 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007653 .dig_in_nid = ALC883_DIGIN_NID,
7654 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7655 .channel_mode = alc883_3ST_2ch_modes,
7656 .input_mux = &alc883_capture_source,
7657 },
7658 [ALC883_3ST_6ch_DIG] = {
7659 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
7660 .init_verbs = { alc883_init_verbs },
7661 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7662 .dac_nids = alc883_dac_nids,
7663 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007664 .dig_in_nid = ALC883_DIGIN_NID,
7665 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
7666 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02007667 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007668 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007669 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007670 [ALC883_3ST_6ch] = {
7671 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
7672 .init_verbs = { alc883_init_verbs },
7673 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7674 .dac_nids = alc883_dac_nids,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007675 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
7676 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02007677 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007678 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007679 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007680 [ALC883_6ST_DIG] = {
7681 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
7682 .init_verbs = { alc883_init_verbs },
7683 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7684 .dac_nids = alc883_dac_nids,
7685 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007686 .dig_in_nid = ALC883_DIGIN_NID,
7687 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
7688 .channel_mode = alc883_sixstack_modes,
7689 .input_mux = &alc883_capture_source,
7690 },
Kailang Yangccc656c2006-10-17 12:32:26 +02007691 [ALC883_TARGA_DIG] = {
7692 .mixers = { alc883_tagra_mixer, alc883_chmode_mixer },
7693 .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
7694 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7695 .dac_nids = alc883_dac_nids,
7696 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02007697 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
7698 .channel_mode = alc883_3ST_6ch_modes,
7699 .need_dac_fix = 1,
7700 .input_mux = &alc883_capture_source,
7701 .unsol_event = alc883_tagra_unsol_event,
7702 .init_hook = alc883_tagra_automute,
7703 },
7704 [ALC883_TARGA_2ch_DIG] = {
7705 .mixers = { alc883_tagra_2ch_mixer},
7706 .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
7707 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7708 .dac_nids = alc883_dac_nids,
7709 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02007710 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7711 .channel_mode = alc883_3ST_2ch_modes,
7712 .input_mux = &alc883_capture_source,
7713 .unsol_event = alc883_tagra_unsol_event,
7714 .init_hook = alc883_tagra_automute,
7715 },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02007716 [ALC883_ACER] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02007717 .mixers = { alc883_base_mixer },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02007718 /* On TravelMate laptops, GPIO 0 enables the internal speaker
7719 * and the headphone jack. Turn this on and rely on the
7720 * standard mute methods whenever the user wants to turn
7721 * these outputs off.
7722 */
7723 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
7724 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7725 .dac_nids = alc883_dac_nids,
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02007726 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7727 .channel_mode = alc883_3ST_2ch_modes,
7728 .input_mux = &alc883_capture_source,
7729 },
Tobin Davis2880a862007-08-07 11:50:26 +02007730 [ALC883_ACER_ASPIRE] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02007731 .mixers = { alc883_acer_aspire_mixer },
Kailang Yangd1a991a2007-08-15 16:21:59 +02007732 .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs },
Tobin Davis2880a862007-08-07 11:50:26 +02007733 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7734 .dac_nids = alc883_dac_nids,
7735 .dig_out_nid = ALC883_DIGOUT_NID,
Tobin Davis2880a862007-08-07 11:50:26 +02007736 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7737 .channel_mode = alc883_3ST_2ch_modes,
7738 .input_mux = &alc883_capture_source,
Takashi Iwai676a9b52007-08-16 15:23:35 +02007739 .unsol_event = alc883_acer_aspire_unsol_event,
7740 .init_hook = alc883_acer_aspire_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +02007741 },
Tobin Davisc07584c2006-10-13 12:32:16 +02007742 [ALC883_MEDION] = {
7743 .mixers = { alc883_fivestack_mixer,
7744 alc883_chmode_mixer },
7745 .init_verbs = { alc883_init_verbs,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007746 alc883_medion_eapd_verbs },
Tobin Davisc07584c2006-10-13 12:32:16 +02007747 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7748 .dac_nids = alc883_dac_nids,
Tobin Davisc07584c2006-10-13 12:32:16 +02007749 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
7750 .channel_mode = alc883_sixstack_modes,
7751 .input_mux = &alc883_capture_source,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007752 },
Kailang Yang272a5272007-05-14 11:00:38 +02007753 [ALC883_MEDION_MD2] = {
7754 .mixers = { alc883_medion_md2_mixer},
7755 .init_verbs = { alc883_init_verbs, alc883_medion_md2_verbs},
7756 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7757 .dac_nids = alc883_dac_nids,
7758 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +02007759 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7760 .channel_mode = alc883_3ST_2ch_modes,
7761 .input_mux = &alc883_capture_source,
7762 .unsol_event = alc883_medion_md2_unsol_event,
7763 .init_hook = alc883_medion_md2_automute,
7764 },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007765 [ALC883_LAPTOP_EAPD] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02007766 .mixers = { alc883_base_mixer },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007767 .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
7768 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7769 .dac_nids = alc883_dac_nids,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007770 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7771 .channel_mode = alc883_3ST_2ch_modes,
7772 .input_mux = &alc883_capture_source,
7773 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007774 [ALC883_LENOVO_101E_2ch] = {
7775 .mixers = { alc883_lenovo_101e_2ch_mixer},
7776 .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
7777 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7778 .dac_nids = alc883_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007779 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7780 .channel_mode = alc883_3ST_2ch_modes,
7781 .input_mux = &alc883_lenovo_101e_capture_source,
7782 .unsol_event = alc883_lenovo_101e_unsol_event,
7783 .init_hook = alc883_lenovo_101e_all_automute,
7784 },
Kailang Yang272a5272007-05-14 11:00:38 +02007785 [ALC883_LENOVO_NB0763] = {
7786 .mixers = { alc883_lenovo_nb0763_mixer },
7787 .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
7788 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7789 .dac_nids = alc883_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02007790 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7791 .channel_mode = alc883_3ST_2ch_modes,
7792 .need_dac_fix = 1,
7793 .input_mux = &alc883_lenovo_nb0763_capture_source,
7794 .unsol_event = alc883_medion_md2_unsol_event,
7795 .init_hook = alc883_medion_md2_automute,
7796 },
7797 [ALC888_LENOVO_MS7195_DIG] = {
7798 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
7799 .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs},
7800 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7801 .dac_nids = alc883_dac_nids,
7802 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +02007803 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
7804 .channel_mode = alc883_3ST_6ch_modes,
7805 .need_dac_fix = 1,
7806 .input_mux = &alc883_capture_source,
7807 .unsol_event = alc883_lenovo_ms7195_unsol_event,
7808 .init_hook = alc888_lenovo_ms7195_front_automute,
Kailang Yang189609a2007-08-20 11:31:23 +02007809 },
7810 [ALC883_HAIER_W66] = {
7811 .mixers = { alc883_tagra_2ch_mixer},
7812 .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs},
7813 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7814 .dac_nids = alc883_dac_nids,
7815 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang189609a2007-08-20 11:31:23 +02007816 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7817 .channel_mode = alc883_3ST_2ch_modes,
7818 .input_mux = &alc883_capture_source,
7819 .unsol_event = alc883_haier_w66_unsol_event,
7820 .init_hook = alc883_haier_w66_automute,
Kailang Yang272a5272007-05-14 11:00:38 +02007821 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007822 [ALC888_6ST_HP] = {
7823 .mixers = { alc888_6st_hp_mixer, alc883_chmode_mixer },
7824 .init_verbs = { alc883_init_verbs, alc888_6st_hp_verbs },
Claudio Matsuokacd1e3b42007-07-06 12:10:01 +02007825 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7826 .dac_nids = alc883_dac_nids,
7827 .dig_out_nid = ALC883_DIGOUT_NID,
Claudio Matsuokacd1e3b42007-07-06 12:10:01 +02007828 .dig_in_nid = ALC883_DIGIN_NID,
7829 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
7830 .channel_mode = alc883_sixstack_modes,
7831 .input_mux = &alc883_capture_source,
7832 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007833 [ALC888_3ST_HP] = {
7834 .mixers = { alc888_3st_hp_mixer, alc883_chmode_mixer },
7835 .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007836 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7837 .dac_nids = alc883_dac_nids,
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007838 .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
7839 .channel_mode = alc888_3st_hp_modes,
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007840 .need_dac_fix = 1,
7841 .input_mux = &alc883_capture_source,
7842 },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007843 [ALC888_6ST_DELL] = {
7844 .mixers = { alc888_6st_dell_mixer, alc883_chmode_mixer },
7845 .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
7846 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7847 .dac_nids = alc883_dac_nids,
7848 .dig_out_nid = ALC883_DIGOUT_NID,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007849 .dig_in_nid = ALC883_DIGIN_NID,
7850 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
7851 .channel_mode = alc883_sixstack_modes,
7852 .input_mux = &alc883_capture_source,
7853 .unsol_event = alc888_6st_dell_unsol_event,
7854 .init_hook = alc888_6st_dell_front_automute,
7855 },
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007856 [ALC883_MITAC] = {
7857 .mixers = { alc883_mitac_mixer },
7858 .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
7859 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
7860 .dac_nids = alc883_dac_nids,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007861 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
7862 .channel_mode = alc883_3ST_2ch_modes,
7863 .input_mux = &alc883_capture_source,
7864 .unsol_event = alc883_mitac_unsol_event,
7865 .init_hook = alc883_mitac_automute,
7866 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007867};
7868
7869
7870/*
7871 * BIOS auto configuration
7872 */
7873static void alc883_auto_set_output_and_unmute(struct hda_codec *codec,
7874 hda_nid_t nid, int pin_type,
7875 int dac_idx)
7876{
7877 /* set as output */
7878 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007879 int idx;
7880
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007881 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007882 if (spec->multiout.dac_nids[dac_idx] == 0x25)
7883 idx = 4;
7884 else
7885 idx = spec->multiout.dac_nids[dac_idx] - 2;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007886 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
7887
7888}
7889
7890static void alc883_auto_init_multi_out(struct hda_codec *codec)
7891{
7892 struct alc_spec *spec = codec->spec;
7893 int i;
7894
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007895 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007896 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007897 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02007898 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007899 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02007900 alc883_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007901 i);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007902 }
7903}
7904
7905static void alc883_auto_init_hp_out(struct hda_codec *codec)
7906{
7907 struct alc_spec *spec = codec->spec;
7908 hda_nid_t pin;
7909
Takashi Iwaieb06ed82006-09-20 17:10:27 +02007910 pin = spec->autocfg.hp_pins[0];
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007911 if (pin) /* connect to front */
7912 /* use dac 0 */
7913 alc883_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007914 pin = spec->autocfg.speaker_pins[0];
7915 if (pin)
7916 alc883_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007917}
7918
7919#define alc883_is_input_pin(nid) alc880_is_input_pin(nid)
7920#define ALC883_PIN_CD_NID ALC880_PIN_CD_NID
7921
7922static void alc883_auto_init_analog_input(struct hda_codec *codec)
7923{
7924 struct alc_spec *spec = codec->spec;
7925 int i;
7926
7927 for (i = 0; i < AUTO_PIN_LAST; i++) {
7928 hda_nid_t nid = spec->autocfg.input_pins[i];
7929 if (alc883_is_input_pin(nid)) {
7930 snd_hda_codec_write(codec, nid, 0,
7931 AC_VERB_SET_PIN_WIDGET_CONTROL,
7932 (i <= AUTO_PIN_FRONT_MIC ?
7933 PIN_VREF80 : PIN_IN));
7934 if (nid != ALC883_PIN_CD_NID)
7935 snd_hda_codec_write(codec, nid, 0,
7936 AC_VERB_SET_AMP_GAIN_MUTE,
7937 AMP_OUT_MUTE);
7938 }
7939 }
7940}
7941
7942/* almost identical with ALC880 parser... */
7943static int alc883_parse_auto_config(struct hda_codec *codec)
7944{
7945 struct alc_spec *spec = codec->spec;
7946 int err = alc880_parse_auto_config(codec);
7947
7948 if (err < 0)
7949 return err;
Takashi Iwai776e1842007-08-29 15:07:11 +02007950 else if (!err)
7951 return 0; /* no config found */
7952
7953 err = alc_auto_add_mic_boost(codec);
7954 if (err < 0)
7955 return err;
7956
7957 /* hack - override the init verbs */
7958 spec->init_verbs[0] = alc883_auto_init_verbs;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007959 spec->mixers[spec->num_mixers] = alc883_capture_mixer;
7960 spec->num_mixers++;
Takashi Iwai776e1842007-08-29 15:07:11 +02007961
7962 return 1; /* config found */
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007963}
7964
7965/* additional initialization for auto-configuration model */
7966static void alc883_auto_init(struct hda_codec *codec)
7967{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007968 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007969 alc883_auto_init_multi_out(codec);
7970 alc883_auto_init_hp_out(codec);
7971 alc883_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007972 if (spec->unsol_event)
7973 alc_sku_automute(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007974}
7975
7976static int patch_alc883(struct hda_codec *codec)
7977{
7978 struct alc_spec *spec;
7979 int err, board_config;
7980
7981 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
7982 if (spec == NULL)
7983 return -ENOMEM;
7984
7985 codec->spec = spec;
7986
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007987 board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST,
7988 alc883_models,
7989 alc883_cfg_tbl);
7990 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007991 printk(KERN_INFO "hda_codec: Unknown model for ALC883, "
7992 "trying auto-probe from BIOS...\n");
7993 board_config = ALC883_AUTO;
7994 }
7995
7996 if (board_config == ALC883_AUTO) {
7997 /* automatic parse from the BIOS config */
7998 err = alc883_parse_auto_config(codec);
7999 if (err < 0) {
8000 alc_free(codec);
8001 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008002 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008003 printk(KERN_INFO
8004 "hda_codec: Cannot set up configuration "
8005 "from BIOS. Using base mode...\n");
8006 board_config = ALC883_3ST_2ch_DIG;
8007 }
8008 }
8009
8010 if (board_config != ALC883_AUTO)
8011 setup_preset(spec, &alc883_presets[board_config]);
8012
8013 spec->stream_name_analog = "ALC883 Analog";
8014 spec->stream_analog_playback = &alc883_pcm_analog_playback;
8015 spec->stream_analog_capture = &alc883_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01008016 spec->stream_analog_alt_capture = &alc883_pcm_analog_alt_capture;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008017
8018 spec->stream_name_digital = "ALC883 Digital";
8019 spec->stream_digital_playback = &alc883_pcm_digital_playback;
8020 spec->stream_digital_capture = &alc883_pcm_digital_capture;
8021
Takashi Iwaie1406342008-02-11 18:32:32 +01008022 spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
8023 spec->adc_nids = alc883_adc_nids;
8024 spec->capsrc_nids = alc883_capsrc_nids;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008025
Takashi Iwai2134ea42008-01-10 16:53:55 +01008026 spec->vmaster_nid = 0x0c;
8027
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008028 codec->patch_ops = alc_patch_ops;
8029 if (board_config == ALC883_AUTO)
8030 spec->init_hook = alc883_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02008031#ifdef CONFIG_SND_HDA_POWER_SAVE
8032 if (!spec->loopback.amplist)
8033 spec->loopback.amplist = alc883_loopbacks;
8034#endif
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008035
8036 return 0;
8037}
8038
8039/*
Kailang Yangdf694da2005-12-05 19:42:22 +01008040 * ALC262 support
8041 */
8042
8043#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID
8044#define ALC262_DIGIN_NID ALC880_DIGIN_NID
8045
8046#define alc262_dac_nids alc260_dac_nids
8047#define alc262_adc_nids alc882_adc_nids
8048#define alc262_adc_nids_alt alc882_adc_nids_alt
8049
8050#define alc262_modes alc260_modes
Takashi Iwaic5f2ea02005-12-06 18:54:31 +01008051#define alc262_capture_source alc882_capture_source
Kailang Yangdf694da2005-12-05 19:42:22 +01008052
8053static struct snd_kcontrol_new alc262_base_mixer[] = {
8054 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8055 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8056 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8057 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8058 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8059 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8060 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8061 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008062 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01008063 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8064 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008065 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01008066 /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01008067 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT), */
Kailang Yangdf694da2005-12-05 19:42:22 +01008068 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
8069 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8070 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8071 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01008072 { } /* end */
Takashi Iwai834be882006-03-01 14:16:17 +01008073};
8074
Kailang Yangccc656c2006-10-17 12:32:26 +02008075static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
8076 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8077 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8078 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8079 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8080 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8081 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8082 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8083 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008084 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008085 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8086 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008087 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008088 /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01008089 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT), */
Kailang Yangccc656c2006-10-17 12:32:26 +02008090 /*HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),*/
8091 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8092 { } /* end */
8093};
8094
Takashi Iwaice875f02008-01-28 18:17:43 +01008095/* update HP, line and mono-out pins according to the master switch */
8096static void alc262_hp_master_update(struct hda_codec *codec)
8097{
8098 struct alc_spec *spec = codec->spec;
8099 int val = spec->master_sw;
8100
8101 /* HP & line-out */
8102 snd_hda_codec_write_cache(codec, 0x1b, 0,
8103 AC_VERB_SET_PIN_WIDGET_CONTROL,
8104 val ? PIN_HP : 0);
8105 snd_hda_codec_write_cache(codec, 0x15, 0,
8106 AC_VERB_SET_PIN_WIDGET_CONTROL,
8107 val ? PIN_HP : 0);
8108 /* mono (speaker) depending on the HP jack sense */
8109 val = val && !spec->jack_present;
8110 snd_hda_codec_write_cache(codec, 0x16, 0,
8111 AC_VERB_SET_PIN_WIDGET_CONTROL,
8112 val ? PIN_OUT : 0);
8113}
8114
8115static void alc262_hp_bpc_automute(struct hda_codec *codec)
8116{
8117 struct alc_spec *spec = codec->spec;
8118 unsigned int presence;
8119 presence = snd_hda_codec_read(codec, 0x1b, 0,
8120 AC_VERB_GET_PIN_SENSE, 0);
8121 spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
8122 alc262_hp_master_update(codec);
8123}
8124
8125static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res)
8126{
8127 if ((res >> 26) != ALC880_HP_EVENT)
8128 return;
8129 alc262_hp_bpc_automute(codec);
8130}
8131
8132static void alc262_hp_wildwest_automute(struct hda_codec *codec)
8133{
8134 struct alc_spec *spec = codec->spec;
8135 unsigned int presence;
8136 presence = snd_hda_codec_read(codec, 0x15, 0,
8137 AC_VERB_GET_PIN_SENSE, 0);
8138 spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
8139 alc262_hp_master_update(codec);
8140}
8141
8142static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec,
8143 unsigned int res)
8144{
8145 if ((res >> 26) != ALC880_HP_EVENT)
8146 return;
8147 alc262_hp_wildwest_automute(codec);
8148}
8149
8150static int alc262_hp_master_sw_get(struct snd_kcontrol *kcontrol,
8151 struct snd_ctl_elem_value *ucontrol)
8152{
8153 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
8154 struct alc_spec *spec = codec->spec;
8155 *ucontrol->value.integer.value = spec->master_sw;
8156 return 0;
8157}
8158
8159static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
8160 struct snd_ctl_elem_value *ucontrol)
8161{
8162 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
8163 struct alc_spec *spec = codec->spec;
8164 int val = !!*ucontrol->value.integer.value;
8165
8166 if (val == spec->master_sw)
8167 return 0;
8168 spec->master_sw = val;
8169 alc262_hp_master_update(codec);
8170 return 1;
8171}
8172
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008173static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
Takashi Iwaice875f02008-01-28 18:17:43 +01008174 {
8175 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8176 .name = "Master Playback Switch",
8177 .info = snd_ctl_boolean_mono_info,
8178 .get = alc262_hp_master_sw_get,
8179 .put = alc262_hp_master_sw_put,
8180 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008181 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8182 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8183 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +01008184 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
8185 HDA_OUTPUT),
8186 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
8187 HDA_OUTPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008188 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8189 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008190 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008191 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8192 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008193 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008194 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8195 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8196 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8197 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8198 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
8199 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT),
8200 HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
8201 HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
8202 { } /* end */
8203};
8204
Kailang Yangcd7509a2007-01-26 18:33:17 +01008205static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
Takashi Iwaice875f02008-01-28 18:17:43 +01008206 {
8207 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8208 .name = "Master Playback Switch",
8209 .info = snd_ctl_boolean_mono_info,
8210 .get = alc262_hp_master_sw_get,
8211 .put = alc262_hp_master_sw_put,
8212 },
Kailang Yangcd7509a2007-01-26 18:33:17 +01008213 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8214 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8215 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8216 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +01008217 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
8218 HDA_OUTPUT),
8219 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
8220 HDA_OUTPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01008221 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
8222 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008223 HDA_CODEC_VOLUME("Front Mic Boost", 0x1a, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01008224 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
8225 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
8226 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8227 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8228 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
8229 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT),
8230 { } /* end */
8231};
8232
8233static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
8234 HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8235 HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008236 HDA_CODEC_VOLUME("Rear Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01008237 { } /* end */
8238};
8239
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008240/* mute/unmute internal speaker according to the hp jack and mute state */
8241static void alc262_hp_t5735_automute(struct hda_codec *codec, int force)
8242{
8243 struct alc_spec *spec = codec->spec;
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008244
8245 if (force || !spec->sense_updated) {
8246 unsigned int present;
8247 present = snd_hda_codec_read(codec, 0x15, 0,
8248 AC_VERB_GET_PIN_SENSE, 0);
Takashi Iwai4bb26132008-01-28 18:12:42 +01008249 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008250 spec->sense_updated = 1;
8251 }
Takashi Iwai4bb26132008-01-28 18:12:42 +01008252 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0, HDA_AMP_MUTE,
8253 spec->jack_present ? HDA_AMP_MUTE : 0);
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008254}
8255
8256static void alc262_hp_t5735_unsol_event(struct hda_codec *codec,
8257 unsigned int res)
8258{
8259 if ((res >> 26) != ALC880_HP_EVENT)
8260 return;
8261 alc262_hp_t5735_automute(codec, 1);
8262}
8263
8264static void alc262_hp_t5735_init_hook(struct hda_codec *codec)
8265{
8266 alc262_hp_t5735_automute(codec, 1);
8267}
8268
8269static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +01008270 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8271 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008272 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8273 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8274 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8275 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8276 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8277 { } /* end */
8278};
8279
8280static struct hda_verb alc262_hp_t5735_verbs[] = {
8281 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8282 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8283
8284 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8285 { }
8286};
8287
Kailang Yang8c427222008-01-10 13:03:59 +01008288static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
Takashi Iwaif2f48e12008-01-28 18:14:43 +01008289 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8290 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01008291 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
8292 HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +01008293 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
8294 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
8295 { } /* end */
8296};
8297
8298static struct hda_verb alc262_hp_rp5700_verbs[] = {
8299 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8300 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8301 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8302 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8303 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8304 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
8305 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
8306 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
8307 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
8308 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
8309 {}
8310};
8311
8312static struct hda_input_mux alc262_hp_rp5700_capture_source = {
8313 .num_items = 1,
8314 .items = {
8315 { "Line", 0x1 },
8316 },
8317};
8318
Takashi Iwai0724ea22007-08-23 00:31:43 +02008319/* bind hp and internal speaker mute (with plug check) */
8320static int alc262_sony_master_sw_put(struct snd_kcontrol *kcontrol,
8321 struct snd_ctl_elem_value *ucontrol)
8322{
8323 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
8324 long *valp = ucontrol->value.integer.value;
8325 int change;
8326
8327 /* change hp mute */
8328 change = snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0,
8329 HDA_AMP_MUTE,
8330 valp[0] ? 0 : HDA_AMP_MUTE);
8331 change |= snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0,
8332 HDA_AMP_MUTE,
8333 valp[1] ? 0 : HDA_AMP_MUTE);
8334 if (change) {
8335 /* change speaker according to HP jack state */
8336 struct alc_spec *spec = codec->spec;
8337 unsigned int mute;
8338 if (spec->jack_present)
8339 mute = HDA_AMP_MUTE;
8340 else
8341 mute = snd_hda_codec_amp_read(codec, 0x15, 0,
8342 HDA_OUTPUT, 0);
8343 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8344 HDA_AMP_MUTE, mute);
8345 }
8346 return change;
8347}
Takashi Iwai5b319542007-07-26 11:49:22 +02008348
Kailang Yang272a5272007-05-14 11:00:38 +02008349static struct snd_kcontrol_new alc262_sony_mixer[] = {
Takashi Iwai0724ea22007-08-23 00:31:43 +02008350 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8351 {
8352 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8353 .name = "Master Playback Switch",
8354 .info = snd_hda_mixer_amp_switch_info,
8355 .get = snd_hda_mixer_amp_switch_get,
8356 .put = alc262_sony_master_sw_put,
8357 .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
8358 },
Kailang Yang272a5272007-05-14 11:00:38 +02008359 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8360 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8361 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8362 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
8363 { } /* end */
8364};
8365
Kailang Yang83c34212007-07-05 11:43:05 +02008366static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
8367 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8368 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8369 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8370 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8371 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8372 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8373 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
8374 { } /* end */
8375};
Kailang Yang272a5272007-05-14 11:00:38 +02008376
Kailang Yangdf694da2005-12-05 19:42:22 +01008377#define alc262_capture_mixer alc882_capture_mixer
8378#define alc262_capture_alt_mixer alc882_capture_alt_mixer
8379
8380/*
8381 * generic initialization of ADC, input mixers and output mixers
8382 */
8383static struct hda_verb alc262_init_verbs[] = {
8384 /*
8385 * Unmute ADC0-2 and set the default input to mic-in
8386 */
8387 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8388 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8389 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8390 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8391 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8392 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8393
Takashi Iwaicb53c622007-08-10 17:21:45 +02008394 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01008395 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008396 * Note: PASD motherboards uses the Line In 2 as the input for
8397 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01008398 */
8399 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02008400 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8401 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8402 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8403 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8404 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01008405
8406 /*
8407 * Set up output mixers (0x0c - 0x0e)
8408 */
8409 /* set vol=0 to output mixers */
8410 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8411 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8412 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8413 /* set up input amps for analog loopback */
8414 /* Amp Indices: DAC = 0, mixer = 1 */
8415 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8416 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8417 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8418 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8419 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8420 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8421
8422 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
8423 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
8424 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
8425 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
8426 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
8427 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
8428
8429 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8430 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8431 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8432 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8433 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8434
8435 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8436 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
8437
8438 /* FIXME: use matrix-type input source selection */
8439 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8440 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8441 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8442 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
8443 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
8444 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
8445 /* Input mixer2 */
8446 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8447 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
8448 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
8449 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
8450 /* Input mixer3 */
8451 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8452 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
8453 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008454 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
Kailang Yangdf694da2005-12-05 19:42:22 +01008455
8456 { }
8457};
8458
Kailang Yangccc656c2006-10-17 12:32:26 +02008459static struct hda_verb alc262_hippo_unsol_verbs[] = {
8460 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
8461 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8462 {}
8463};
8464
8465static struct hda_verb alc262_hippo1_unsol_verbs[] = {
8466 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
8467 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
8468 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
8469
8470 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
8471 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8472 {}
8473};
8474
Kailang Yang272a5272007-05-14 11:00:38 +02008475static struct hda_verb alc262_sony_unsol_verbs[] = {
8476 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
8477 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8478 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic
8479
8480 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
8481 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8482};
8483
Kailang Yangccc656c2006-10-17 12:32:26 +02008484/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai5b319542007-07-26 11:49:22 +02008485static void alc262_hippo_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02008486{
8487 struct alc_spec *spec = codec->spec;
8488 unsigned int mute;
Takashi Iwai5b319542007-07-26 11:49:22 +02008489 unsigned int present;
Kailang Yangccc656c2006-10-17 12:32:26 +02008490
Takashi Iwai5b319542007-07-26 11:49:22 +02008491 /* need to execute and sync at first */
8492 snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
8493 present = snd_hda_codec_read(codec, 0x15, 0,
8494 AC_VERB_GET_PIN_SENSE, 0);
8495 spec->jack_present = (present & 0x80000000) != 0;
Kailang Yangccc656c2006-10-17 12:32:26 +02008496 if (spec->jack_present) {
8497 /* mute internal speaker */
Takashi Iwai47fd8302007-08-10 17:11:07 +02008498 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8499 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangccc656c2006-10-17 12:32:26 +02008500 } else {
8501 /* unmute internal speaker if necessary */
8502 mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
Takashi Iwai47fd8302007-08-10 17:11:07 +02008503 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8504 HDA_AMP_MUTE, mute);
Kailang Yangccc656c2006-10-17 12:32:26 +02008505 }
8506}
8507
8508/* unsolicited event for HP jack sensing */
8509static void alc262_hippo_unsol_event(struct hda_codec *codec,
8510 unsigned int res)
8511{
8512 if ((res >> 26) != ALC880_HP_EVENT)
8513 return;
Takashi Iwai5b319542007-07-26 11:49:22 +02008514 alc262_hippo_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02008515}
8516
Takashi Iwai5b319542007-07-26 11:49:22 +02008517static void alc262_hippo1_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02008518{
Kailang Yangccc656c2006-10-17 12:32:26 +02008519 unsigned int mute;
Takashi Iwai5b319542007-07-26 11:49:22 +02008520 unsigned int present;
Kailang Yangccc656c2006-10-17 12:32:26 +02008521
Takashi Iwai5b319542007-07-26 11:49:22 +02008522 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
8523 present = snd_hda_codec_read(codec, 0x1b, 0,
8524 AC_VERB_GET_PIN_SENSE, 0);
8525 present = (present & 0x80000000) != 0;
8526 if (present) {
Kailang Yangccc656c2006-10-17 12:32:26 +02008527 /* mute internal speaker */
Takashi Iwai47fd8302007-08-10 17:11:07 +02008528 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8529 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangccc656c2006-10-17 12:32:26 +02008530 } else {
8531 /* unmute internal speaker if necessary */
8532 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
Takashi Iwai47fd8302007-08-10 17:11:07 +02008533 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8534 HDA_AMP_MUTE, mute);
Kailang Yangccc656c2006-10-17 12:32:26 +02008535 }
8536}
8537
8538/* unsolicited event for HP jack sensing */
8539static void alc262_hippo1_unsol_event(struct hda_codec *codec,
8540 unsigned int res)
8541{
8542 if ((res >> 26) != ALC880_HP_EVENT)
8543 return;
Takashi Iwai5b319542007-07-26 11:49:22 +02008544 alc262_hippo1_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02008545}
8546
Takashi Iwai834be882006-03-01 14:16:17 +01008547/*
8548 * fujitsu model
8549 * 0x14 = headphone/spdif-out, 0x15 = internal speaker
8550 */
8551
8552#define ALC_HP_EVENT 0x37
8553
8554static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
8555 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
8556 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8557 {}
8558};
8559
8560static struct hda_input_mux alc262_fujitsu_capture_source = {
Takashi Iwai39d3ed32007-10-12 15:03:48 +02008561 .num_items = 3,
Takashi Iwai834be882006-03-01 14:16:17 +01008562 .items = {
8563 { "Mic", 0x0 },
Takashi Iwai39d3ed32007-10-12 15:03:48 +02008564 { "Int Mic", 0x1 },
Takashi Iwai834be882006-03-01 14:16:17 +01008565 { "CD", 0x4 },
8566 },
8567};
8568
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008569static struct hda_input_mux alc262_HP_capture_source = {
8570 .num_items = 5,
8571 .items = {
8572 { "Mic", 0x0 },
zhejiangaccbe492007-08-31 12:36:05 +02008573 { "Front Mic", 0x1 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008574 { "Line", 0x2 },
8575 { "CD", 0x4 },
8576 { "AUX IN", 0x6 },
8577 },
8578};
8579
zhejiangaccbe492007-08-31 12:36:05 +02008580static struct hda_input_mux alc262_HP_D7000_capture_source = {
8581 .num_items = 4,
8582 .items = {
8583 { "Mic", 0x0 },
8584 { "Front Mic", 0x2 },
8585 { "Line", 0x1 },
8586 { "CD", 0x4 },
8587 },
8588};
8589
Takashi Iwai834be882006-03-01 14:16:17 +01008590/* mute/unmute internal speaker according to the hp jack and mute state */
8591static void alc262_fujitsu_automute(struct hda_codec *codec, int force)
8592{
8593 struct alc_spec *spec = codec->spec;
8594 unsigned int mute;
8595
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008596 if (force || !spec->sense_updated) {
Takashi Iwai834be882006-03-01 14:16:17 +01008597 unsigned int present;
8598 /* need to execute and sync at first */
8599 snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
8600 present = snd_hda_codec_read(codec, 0x14, 0,
8601 AC_VERB_GET_PIN_SENSE, 0);
8602 spec->jack_present = (present & 0x80000000) != 0;
8603 spec->sense_updated = 1;
8604 }
8605 if (spec->jack_present) {
8606 /* mute internal speaker */
Takashi Iwai47fd8302007-08-10 17:11:07 +02008607 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8608 HDA_AMP_MUTE, HDA_AMP_MUTE);
Takashi Iwai834be882006-03-01 14:16:17 +01008609 } else {
8610 /* unmute internal speaker if necessary */
8611 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
Takashi Iwai47fd8302007-08-10 17:11:07 +02008612 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8613 HDA_AMP_MUTE, mute);
Takashi Iwai834be882006-03-01 14:16:17 +01008614 }
8615}
8616
8617/* unsolicited event for HP jack sensing */
8618static void alc262_fujitsu_unsol_event(struct hda_codec *codec,
8619 unsigned int res)
8620{
8621 if ((res >> 26) != ALC_HP_EVENT)
8622 return;
8623 alc262_fujitsu_automute(codec, 1);
8624}
8625
8626/* bind volumes of both NID 0x0c and 0x0d */
Takashi Iwaicca3b372007-08-10 17:12:15 +02008627static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
8628 .ops = &snd_hda_bind_vol,
8629 .values = {
8630 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
8631 HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
8632 0
8633 },
8634};
Takashi Iwai834be882006-03-01 14:16:17 +01008635
8636/* bind hp and internal speaker mute (with plug check) */
8637static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
8638 struct snd_ctl_elem_value *ucontrol)
8639{
8640 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
8641 long *valp = ucontrol->value.integer.value;
8642 int change;
8643
8644 change = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02008645 HDA_AMP_MUTE,
8646 valp[0] ? 0 : HDA_AMP_MUTE);
Takashi Iwai834be882006-03-01 14:16:17 +01008647 change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02008648 HDA_AMP_MUTE,
8649 valp[1] ? 0 : HDA_AMP_MUTE);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02008650 if (change)
8651 alc262_fujitsu_automute(codec, 0);
Takashi Iwai834be882006-03-01 14:16:17 +01008652 return change;
8653}
8654
8655static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02008656 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai834be882006-03-01 14:16:17 +01008657 {
8658 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8659 .name = "Master Playback Switch",
8660 .info = snd_hda_mixer_amp_switch_info,
8661 .get = snd_hda_mixer_amp_switch_get,
8662 .put = alc262_fujitsu_master_sw_put,
8663 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
8664 },
8665 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8666 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8667 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8668 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8669 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai39d3ed32007-10-12 15:03:48 +02008670 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8671 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8672 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +01008673 { } /* end */
8674};
8675
Takashi Iwai304dcaa2006-07-25 14:51:16 +02008676/* additional init verbs for Benq laptops */
8677static struct hda_verb alc262_EAPD_verbs[] = {
8678 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
8679 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
8680 {}
8681};
8682
Kailang Yang83c34212007-07-05 11:43:05 +02008683static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
8684 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8685 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
8686
8687 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
8688 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
8689 {}
8690};
8691
Tobin Davisf651b502007-10-26 12:40:47 +02008692/* Samsung Q1 Ultra Vista model setup */
8693static struct snd_kcontrol_new alc262_ultra_mixer[] = {
8694 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8695 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8696 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8697 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8698 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
8699 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
8700 { } /* end */
8701};
8702
8703static struct hda_verb alc262_ultra_verbs[] = {
8704 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
8705 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8706 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
8707 /* Mic is on Node 0x19 */
8708 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
8709 {0x22, AC_VERB_SET_CONNECT_SEL, 0x01},
8710 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
8711 {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
8712 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
8713 {0x24, AC_VERB_SET_CONNECT_SEL, 0x01},
8714 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
8715 {}
8716};
8717
8718static struct hda_input_mux alc262_ultra_capture_source = {
8719 .num_items = 1,
8720 .items = {
8721 { "Mic", 0x1 },
8722 },
8723};
8724
8725/* mute/unmute internal speaker according to the hp jack and mute state */
8726static void alc262_ultra_automute(struct hda_codec *codec)
8727{
8728 struct alc_spec *spec = codec->spec;
8729 unsigned int mute;
8730 unsigned int present;
8731
8732 /* need to execute and sync at first */
8733 snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
8734 present = snd_hda_codec_read(codec, 0x15, 0,
8735 AC_VERB_GET_PIN_SENSE, 0);
8736 spec->jack_present = (present & 0x80000000) != 0;
8737 if (spec->jack_present) {
8738 /* mute internal speaker */
8739 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8740 HDA_AMP_MUTE, HDA_AMP_MUTE);
8741 } else {
8742 /* unmute internal speaker if necessary */
8743 mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
8744 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8745 HDA_AMP_MUTE, mute);
8746 }
8747}
8748
8749/* unsolicited event for HP jack sensing */
8750static void alc262_ultra_unsol_event(struct hda_codec *codec,
8751 unsigned int res)
8752{
8753 if ((res >> 26) != ALC880_HP_EVENT)
8754 return;
8755 alc262_ultra_automute(codec);
8756}
8757
Kailang Yangdf694da2005-12-05 19:42:22 +01008758/* add playback controls from the parsed DAC table */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008759static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
8760 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +01008761{
8762 hda_nid_t nid;
8763 int err;
8764
8765 spec->multiout.num_dacs = 1; /* only use one dac */
8766 spec->multiout.dac_nids = spec->private_dac_nids;
8767 spec->multiout.dac_nids[0] = 2;
8768
8769 nid = cfg->line_out_pins[0];
8770 if (nid) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008771 err = add_control(spec, ALC_CTL_WIDGET_VOL,
8772 "Front Playback Volume",
8773 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT));
8774 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008775 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008776 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
8777 "Front Playback Switch",
8778 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
8779 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008780 return err;
8781 }
8782
Takashi Iwai82bc9552006-03-21 11:24:42 +01008783 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01008784 if (nid) {
8785 if (nid == 0x16) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008786 err = add_control(spec, ALC_CTL_WIDGET_VOL,
8787 "Speaker Playback Volume",
8788 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
8789 HDA_OUTPUT));
8790 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008791 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008792 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
8793 "Speaker Playback Switch",
8794 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
8795 HDA_OUTPUT));
8796 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008797 return err;
8798 } else {
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, 3, 0,
8802 HDA_OUTPUT));
8803 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008804 return err;
8805 }
8806 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02008807 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01008808 if (nid) {
8809 /* spec->multiout.hp_nid = 2; */
8810 if (nid == 0x16) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008811 err = add_control(spec, ALC_CTL_WIDGET_VOL,
8812 "Headphone Playback Volume",
8813 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
8814 HDA_OUTPUT));
8815 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008816 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008817 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
8818 "Headphone Playback Switch",
8819 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
8820 HDA_OUTPUT));
8821 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008822 return err;
8823 } else {
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, 3, 0,
8827 HDA_OUTPUT));
8828 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01008829 return err;
8830 }
8831 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008832 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01008833}
8834
8835/* identical with ALC880 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008836#define alc262_auto_create_analog_input_ctls \
8837 alc880_auto_create_analog_input_ctls
Kailang Yangdf694da2005-12-05 19:42:22 +01008838
8839/*
8840 * generic initialization of ADC, input mixers and output mixers
8841 */
8842static struct hda_verb alc262_volume_init_verbs[] = {
8843 /*
8844 * Unmute ADC0-2 and set the default input to mic-in
8845 */
8846 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8847 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8848 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8849 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8850 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8851 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8852
Takashi Iwaicb53c622007-08-10 17:21:45 +02008853 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01008854 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008855 * Note: PASD motherboards uses the Line In 2 as the input for
8856 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01008857 */
8858 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02008859 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8860 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8861 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8862 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8863 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01008864
8865 /*
8866 * Set up output mixers (0x0c - 0x0f)
8867 */
8868 /* set vol=0 to output mixers */
8869 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8870 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8871 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8872
8873 /* set up input amps for analog loopback */
8874 /* Amp Indices: DAC = 0, mixer = 1 */
8875 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8876 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8877 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8878 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8879 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8880 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8881
8882 /* FIXME: use matrix-type input source selection */
8883 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8884 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8885 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8886 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
8887 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
8888 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
8889 /* Input mixer2 */
8890 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8891 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
8892 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
8893 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
8894 /* Input mixer3 */
8895 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8896 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
8897 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
8898 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
8899
8900 { }
8901};
8902
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008903static struct hda_verb alc262_HP_BPC_init_verbs[] = {
8904 /*
8905 * Unmute ADC0-2 and set the default input to mic-in
8906 */
8907 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8908 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8909 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8910 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8911 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8912 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8913
Takashi Iwaicb53c622007-08-10 17:21:45 +02008914 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008915 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008916 * Note: PASD motherboards uses the Line In 2 as the input for
8917 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008918 */
8919 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02008920 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8921 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8922 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8923 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8924 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8925 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
8926 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008927
8928 /*
8929 * Set up output mixers (0x0c - 0x0e)
8930 */
8931 /* set vol=0 to output mixers */
8932 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8933 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8934 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8935
8936 /* set up input amps for analog loopback */
8937 /* Amp Indices: DAC = 0, mixer = 1 */
8938 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8939 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8940 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8941 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8942 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8943 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8944
Takashi Iwaice875f02008-01-28 18:17:43 +01008945 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008946 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8947 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8948
8949 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8950 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8951
8952 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
8953 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8954
8955 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
8956 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
8957 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
8958 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
8959 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
8960
8961 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
8962 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
8963 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
8964 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
8965 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
8966 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
8967
8968
8969 /* FIXME: use matrix-type input source selection */
8970 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8971 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8972 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8973 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
8974 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
8975 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
8976 /* Input mixer2 */
8977 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8978 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
8979 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
8980 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
8981 /* Input mixer3 */
8982 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
8983 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
8984 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
8985 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
8986
Takashi Iwaice875f02008-01-28 18:17:43 +01008987 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8988
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008989 { }
8990};
8991
Kailang Yangcd7509a2007-01-26 18:33:17 +01008992static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
8993 /*
8994 * Unmute ADC0-2 and set the default input to mic-in
8995 */
8996 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8997 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8998 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8999 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9000 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
9001 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9002
Takashi Iwaicb53c622007-08-10 17:21:45 +02009003 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangcd7509a2007-01-26 18:33:17 +01009004 * mixer widget
9005 * Note: PASD motherboards uses the Line In 2 as the input for front
9006 * panel mic (mic 2)
9007 */
9008 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02009009 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9010 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9011 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
9012 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
9013 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
9014 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
9015 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
9016 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Kailang Yangcd7509a2007-01-26 18:33:17 +01009017 /*
9018 * Set up output mixers (0x0c - 0x0e)
9019 */
9020 /* set vol=0 to output mixers */
9021 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9022 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9023 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9024
9025 /* set up input amps for analog loopback */
9026 /* Amp Indices: DAC = 0, mixer = 1 */
9027 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9028 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9029 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9030 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9031 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9032 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9033
9034
9035 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
9036 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
9037 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
9038 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
9039 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
9040 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
9041 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
9042
9043 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
9044 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
9045
9046 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9047 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
9048
9049 /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
9050 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9051 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9052 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
9053 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9054 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9055
9056 /* FIXME: use matrix-type input source selection */
9057 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
9058 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
9059 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
9060 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
9061 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
9062 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
9063 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
9064 /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
9065 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
9066 /* Input mixer2 */
9067 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9068 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
9069 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
9070 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
9071 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
9072 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
9073 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
9074 /* Input mixer3 */
9075 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9076 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
9077 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
9078 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
9079 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
9080 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
9081 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
9082
Takashi Iwaice875f02008-01-28 18:17:43 +01009083 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9084
Kailang Yangcd7509a2007-01-26 18:33:17 +01009085 { }
9086};
9087
Takashi Iwaicb53c622007-08-10 17:21:45 +02009088#ifdef CONFIG_SND_HDA_POWER_SAVE
9089#define alc262_loopbacks alc880_loopbacks
9090#endif
9091
Kailang Yangdf694da2005-12-05 19:42:22 +01009092/* pcm configuration: identiacal with ALC880 */
9093#define alc262_pcm_analog_playback alc880_pcm_analog_playback
9094#define alc262_pcm_analog_capture alc880_pcm_analog_capture
9095#define alc262_pcm_digital_playback alc880_pcm_digital_playback
9096#define alc262_pcm_digital_capture alc880_pcm_digital_capture
9097
9098/*
9099 * BIOS auto configuration
9100 */
9101static int alc262_parse_auto_config(struct hda_codec *codec)
9102{
9103 struct alc_spec *spec = codec->spec;
9104 int err;
9105 static hda_nid_t alc262_ignore[] = { 0x1d, 0 };
9106
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009107 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
9108 alc262_ignore);
9109 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009110 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009111 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +01009112 return 0; /* can't find valid BIOS pin config */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009113 err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
9114 if (err < 0)
9115 return err;
9116 err = alc262_auto_create_analog_input_ctls(spec, &spec->autocfg);
9117 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009118 return err;
9119
9120 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
9121
9122 if (spec->autocfg.dig_out_pin)
9123 spec->multiout.dig_out_nid = ALC262_DIGOUT_NID;
9124 if (spec->autocfg.dig_in_pin)
9125 spec->dig_in_nid = ALC262_DIGIN_NID;
9126
9127 if (spec->kctl_alloc)
9128 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
9129
9130 spec->init_verbs[spec->num_init_verbs++] = alc262_volume_init_verbs;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02009131 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +01009132 spec->input_mux = &spec->private_imux;
9133
Takashi Iwai776e1842007-08-29 15:07:11 +02009134 err = alc_auto_add_mic_boost(codec);
9135 if (err < 0)
9136 return err;
9137
Kailang Yangdf694da2005-12-05 19:42:22 +01009138 return 1;
9139}
9140
9141#define alc262_auto_init_multi_out alc882_auto_init_multi_out
9142#define alc262_auto_init_hp_out alc882_auto_init_hp_out
9143#define alc262_auto_init_analog_input alc882_auto_init_analog_input
9144
9145
9146/* init callback for auto-configuration model -- overriding the default init */
Takashi Iwaiae6b8132006-03-03 16:47:17 +01009147static void alc262_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01009148{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01009149 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01009150 alc262_auto_init_multi_out(codec);
9151 alc262_auto_init_hp_out(codec);
9152 alc262_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01009153 if (spec->unsol_event)
9154 alc_sku_automute(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01009155}
9156
9157/*
9158 * configuration and preset
9159 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009160static const char *alc262_models[ALC262_MODEL_LAST] = {
9161 [ALC262_BASIC] = "basic",
9162 [ALC262_HIPPO] = "hippo",
9163 [ALC262_HIPPO_1] = "hippo_1",
9164 [ALC262_FUJITSU] = "fujitsu",
9165 [ALC262_HP_BPC] = "hp-bpc",
Kailang Yangcd7509a2007-01-26 18:33:17 +01009166 [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
Takashi Iwai61dc35d2007-11-14 12:26:44 +01009167 [ALC262_HP_TC_T5735] = "hp-tc-t5735",
Kailang Yang8c427222008-01-10 13:03:59 +01009168 [ALC262_HP_RP5700] = "hp-rp5700",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009169 [ALC262_BENQ_ED8] = "benq",
Takashi Iwai0f405022007-07-06 12:24:11 +02009170 [ALC262_BENQ_T31] = "benq-t31",
9171 [ALC262_SONY_ASSAMD] = "sony-assamd",
Tobin Davisf651b502007-10-26 12:40:47 +02009172 [ALC262_ULTRA] = "ultra",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009173 [ALC262_AUTO] = "auto",
9174};
9175
9176static struct snd_pci_quirk alc262_cfg_tbl[] = {
9177 SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
9178 SND_PCI_QUIRK(0x103c, 0x12fe, "HP xw9400", ALC262_HP_BPC),
Kailang Yang7d87de22007-06-05 12:17:21 +02009179 SND_PCI_QUIRK(0x103c, 0x12ff, "HP xw4550", ALC262_HP_BPC),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009180 SND_PCI_QUIRK(0x103c, 0x1306, "HP xw8600", ALC262_HP_BPC),
9181 SND_PCI_QUIRK(0x103c, 0x1307, "HP xw6600", ALC262_HP_BPC),
Kailang Yang7d87de22007-06-05 12:17:21 +02009182 SND_PCI_QUIRK(0x103c, 0x1308, "HP xw4600", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +01009183 SND_PCI_QUIRK(0x103c, 0x1309, "HP xw4*00", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +01009184 SND_PCI_QUIRK(0x103c, 0x130a, "HP xw6*00", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +01009185 SND_PCI_QUIRK(0x103c, 0x130b, "HP xw8*00", ALC262_HP_BPC),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009186 SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009187 SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009188 SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009189 SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009190 SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009191 SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009192 SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009193 SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009194 SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
9195 SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
9196 SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009197 SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
9198 ALC262_HP_TC_T5735),
Kailang Yang8c427222008-01-10 13:03:59 +01009199 SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009200 SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009201 SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009202 SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
9203 SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD),
9204 SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009205 SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
Tony Vroon3f1eeae2008-02-25 16:44:13 +01009206 SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009207 SND_PCI_QUIRK(0x144d, 0xc032, "Samsung Q1 Ultra", ALC262_ULTRA),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009208 SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
Kailang Yang83c34212007-07-05 11:43:05 +02009209 SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009210 SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
Kailang Yangdf694da2005-12-05 19:42:22 +01009211 {}
9212};
9213
9214static struct alc_config_preset alc262_presets[] = {
9215 [ALC262_BASIC] = {
9216 .mixers = { alc262_base_mixer },
9217 .init_verbs = { alc262_init_verbs },
9218 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9219 .dac_nids = alc262_dac_nids,
9220 .hp_nid = 0x03,
9221 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9222 .channel_mode = alc262_modes,
Takashi Iwaia3bcba32005-12-06 19:05:29 +01009223 .input_mux = &alc262_capture_source,
Kailang Yangdf694da2005-12-05 19:42:22 +01009224 },
Kailang Yangccc656c2006-10-17 12:32:26 +02009225 [ALC262_HIPPO] = {
9226 .mixers = { alc262_base_mixer },
9227 .init_verbs = { alc262_init_verbs, alc262_hippo_unsol_verbs},
9228 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9229 .dac_nids = alc262_dac_nids,
9230 .hp_nid = 0x03,
9231 .dig_out_nid = ALC262_DIGOUT_NID,
9232 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9233 .channel_mode = alc262_modes,
9234 .input_mux = &alc262_capture_source,
9235 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +02009236 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +02009237 },
9238 [ALC262_HIPPO_1] = {
9239 .mixers = { alc262_hippo1_mixer },
9240 .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
9241 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9242 .dac_nids = alc262_dac_nids,
9243 .hp_nid = 0x02,
9244 .dig_out_nid = ALC262_DIGOUT_NID,
9245 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9246 .channel_mode = alc262_modes,
9247 .input_mux = &alc262_capture_source,
9248 .unsol_event = alc262_hippo1_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +02009249 .init_hook = alc262_hippo1_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +02009250 },
Takashi Iwai834be882006-03-01 14:16:17 +01009251 [ALC262_FUJITSU] = {
9252 .mixers = { alc262_fujitsu_mixer },
Takashi Iwai39d3ed32007-10-12 15:03:48 +02009253 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
9254 alc262_fujitsu_unsol_verbs },
Takashi Iwai834be882006-03-01 14:16:17 +01009255 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9256 .dac_nids = alc262_dac_nids,
9257 .hp_nid = 0x03,
9258 .dig_out_nid = ALC262_DIGOUT_NID,
9259 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9260 .channel_mode = alc262_modes,
9261 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01009262 .unsol_event = alc262_fujitsu_unsol_event,
Takashi Iwai834be882006-03-01 14:16:17 +01009263 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009264 [ALC262_HP_BPC] = {
9265 .mixers = { alc262_HP_BPC_mixer },
9266 .init_verbs = { alc262_HP_BPC_init_verbs },
9267 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9268 .dac_nids = alc262_dac_nids,
9269 .hp_nid = 0x03,
9270 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9271 .channel_mode = alc262_modes,
9272 .input_mux = &alc262_HP_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +01009273 .unsol_event = alc262_hp_bpc_unsol_event,
9274 .init_hook = alc262_hp_bpc_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009275 },
Kailang Yangcd7509a2007-01-26 18:33:17 +01009276 [ALC262_HP_BPC_D7000_WF] = {
9277 .mixers = { alc262_HP_BPC_WildWest_mixer },
9278 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
9279 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9280 .dac_nids = alc262_dac_nids,
9281 .hp_nid = 0x03,
9282 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9283 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +02009284 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +01009285 .unsol_event = alc262_hp_wildwest_unsol_event,
9286 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009287 },
Kailang Yangcd7509a2007-01-26 18:33:17 +01009288 [ALC262_HP_BPC_D7000_WL] = {
9289 .mixers = { alc262_HP_BPC_WildWest_mixer,
9290 alc262_HP_BPC_WildWest_option_mixer },
9291 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
9292 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9293 .dac_nids = alc262_dac_nids,
9294 .hp_nid = 0x03,
9295 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9296 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +02009297 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +01009298 .unsol_event = alc262_hp_wildwest_unsol_event,
9299 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009300 },
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009301 [ALC262_HP_TC_T5735] = {
9302 .mixers = { alc262_hp_t5735_mixer },
9303 .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
9304 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9305 .dac_nids = alc262_dac_nids,
9306 .hp_nid = 0x03,
9307 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9308 .channel_mode = alc262_modes,
9309 .input_mux = &alc262_capture_source,
9310 .unsol_event = alc262_hp_t5735_unsol_event,
9311 .init_hook = alc262_hp_t5735_init_hook,
Kailang Yang8c427222008-01-10 13:03:59 +01009312 },
9313 [ALC262_HP_RP5700] = {
9314 .mixers = { alc262_hp_rp5700_mixer },
9315 .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
9316 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9317 .dac_nids = alc262_dac_nids,
9318 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9319 .channel_mode = alc262_modes,
9320 .input_mux = &alc262_hp_rp5700_capture_source,
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009321 },
Takashi Iwai304dcaa2006-07-25 14:51:16 +02009322 [ALC262_BENQ_ED8] = {
9323 .mixers = { alc262_base_mixer },
9324 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
9325 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9326 .dac_nids = alc262_dac_nids,
9327 .hp_nid = 0x03,
9328 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9329 .channel_mode = alc262_modes,
9330 .input_mux = &alc262_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009331 },
Kailang Yang272a5272007-05-14 11:00:38 +02009332 [ALC262_SONY_ASSAMD] = {
9333 .mixers = { alc262_sony_mixer },
9334 .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs},
9335 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9336 .dac_nids = alc262_dac_nids,
9337 .hp_nid = 0x02,
9338 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9339 .channel_mode = alc262_modes,
9340 .input_mux = &alc262_capture_source,
9341 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +02009342 .init_hook = alc262_hippo_automute,
Kailang Yang83c34212007-07-05 11:43:05 +02009343 },
9344 [ALC262_BENQ_T31] = {
9345 .mixers = { alc262_benq_t31_mixer },
9346 .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs, alc262_hippo_unsol_verbs },
9347 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9348 .dac_nids = alc262_dac_nids,
9349 .hp_nid = 0x03,
9350 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9351 .channel_mode = alc262_modes,
9352 .input_mux = &alc262_capture_source,
9353 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +02009354 .init_hook = alc262_hippo_automute,
Kailang Yang272a5272007-05-14 11:00:38 +02009355 },
Tobin Davisf651b502007-10-26 12:40:47 +02009356 [ALC262_ULTRA] = {
9357 .mixers = { alc262_ultra_mixer },
9358 .init_verbs = { alc262_init_verbs, alc262_ultra_verbs },
9359 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
9360 .dac_nids = alc262_dac_nids,
9361 .hp_nid = 0x03,
9362 .dig_out_nid = ALC262_DIGOUT_NID,
9363 .num_channel_mode = ARRAY_SIZE(alc262_modes),
9364 .channel_mode = alc262_modes,
9365 .input_mux = &alc262_ultra_capture_source,
9366 .unsol_event = alc262_ultra_unsol_event,
9367 .init_hook = alc262_ultra_automute,
9368 },
Kailang Yangdf694da2005-12-05 19:42:22 +01009369};
9370
9371static int patch_alc262(struct hda_codec *codec)
9372{
9373 struct alc_spec *spec;
9374 int board_config;
9375 int err;
9376
Robert P. J. Daydc041e02006-12-19 14:44:15 +01009377 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +01009378 if (spec == NULL)
9379 return -ENOMEM;
9380
9381 codec->spec = spec;
9382#if 0
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009383 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
9384 * under-run
9385 */
Kailang Yangdf694da2005-12-05 19:42:22 +01009386 {
9387 int tmp;
9388 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
9389 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
9390 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
9391 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
9392 }
9393#endif
9394
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009395 board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
9396 alc262_models,
9397 alc262_cfg_tbl);
Kailang Yangcd7509a2007-01-26 18:33:17 +01009398
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009399 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009400 printk(KERN_INFO "hda_codec: Unknown model for ALC262, "
9401 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01009402 board_config = ALC262_AUTO;
9403 }
9404
9405 if (board_config == ALC262_AUTO) {
9406 /* automatic parse from the BIOS config */
9407 err = alc262_parse_auto_config(codec);
9408 if (err < 0) {
9409 alc_free(codec);
9410 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009411 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009412 printk(KERN_INFO
9413 "hda_codec: Cannot set up configuration "
9414 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01009415 board_config = ALC262_BASIC;
9416 }
9417 }
9418
9419 if (board_config != ALC262_AUTO)
9420 setup_preset(spec, &alc262_presets[board_config]);
9421
9422 spec->stream_name_analog = "ALC262 Analog";
9423 spec->stream_analog_playback = &alc262_pcm_analog_playback;
9424 spec->stream_analog_capture = &alc262_pcm_analog_capture;
9425
9426 spec->stream_name_digital = "ALC262 Digital";
9427 spec->stream_digital_playback = &alc262_pcm_digital_playback;
9428 spec->stream_digital_capture = &alc262_pcm_digital_capture;
9429
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009430 if (!spec->adc_nids && spec->input_mux) {
Kailang Yangdf694da2005-12-05 19:42:22 +01009431 /* check whether NID 0x07 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +01009432 unsigned int wcap = get_wcaps(codec, 0x07);
9433
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009434 /* get type */
9435 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Kailang Yangdf694da2005-12-05 19:42:22 +01009436 if (wcap != AC_WID_AUD_IN) {
9437 spec->adc_nids = alc262_adc_nids_alt;
9438 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids_alt);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009439 spec->mixers[spec->num_mixers] =
9440 alc262_capture_alt_mixer;
Kailang Yangdf694da2005-12-05 19:42:22 +01009441 spec->num_mixers++;
9442 } else {
9443 spec->adc_nids = alc262_adc_nids;
9444 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids);
9445 spec->mixers[spec->num_mixers] = alc262_capture_mixer;
9446 spec->num_mixers++;
9447 }
9448 }
9449
Takashi Iwai2134ea42008-01-10 16:53:55 +01009450 spec->vmaster_nid = 0x0c;
9451
Kailang Yangdf694da2005-12-05 19:42:22 +01009452 codec->patch_ops = alc_patch_ops;
9453 if (board_config == ALC262_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01009454 spec->init_hook = alc262_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02009455#ifdef CONFIG_SND_HDA_POWER_SAVE
9456 if (!spec->loopback.amplist)
9457 spec->loopback.amplist = alc262_loopbacks;
9458#endif
Takashi Iwai834be882006-03-01 14:16:17 +01009459
Kailang Yangdf694da2005-12-05 19:42:22 +01009460 return 0;
9461}
9462
Kailang Yangdf694da2005-12-05 19:42:22 +01009463/*
Kailang Yanga361d842007-06-05 12:30:55 +02009464 * ALC268 channel source setting (2 channel)
9465 */
9466#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID
9467#define alc268_modes alc260_modes
9468
9469static hda_nid_t alc268_dac_nids[2] = {
9470 /* front, hp */
9471 0x02, 0x03
9472};
9473
9474static hda_nid_t alc268_adc_nids[2] = {
9475 /* ADC0-1 */
9476 0x08, 0x07
9477};
9478
9479static hda_nid_t alc268_adc_nids_alt[1] = {
9480 /* ADC0 */
9481 0x08
9482};
9483
Takashi Iwaie1406342008-02-11 18:32:32 +01009484static hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
9485
Kailang Yanga361d842007-06-05 12:30:55 +02009486static struct snd_kcontrol_new alc268_base_mixer[] = {
9487 /* output mixer control */
9488 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
9489 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9490 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
9491 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai33bf17a2007-08-21 11:51:42 +02009492 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9493 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
9494 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Kailang Yanga361d842007-06-05 12:30:55 +02009495 { }
9496};
9497
Kailang Yangd1a991a2007-08-15 16:21:59 +02009498static struct hda_verb alc268_eapd_verbs[] = {
9499 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
9500 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
9501 { }
9502};
9503
Takashi Iwaid2738092007-08-16 14:59:45 +02009504/* Toshiba specific */
9505#define alc268_toshiba_automute alc262_hippo_automute
9506
9507static struct hda_verb alc268_toshiba_verbs[] = {
9508 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9509 { } /* end */
9510};
9511
9512/* Acer specific */
Takashi Iwai889c4392007-08-23 18:56:52 +02009513/* bind volumes of both NID 0x02 and 0x03 */
Takashi Iwai6bc96852007-08-17 09:02:12 +02009514static struct hda_bind_ctls alc268_acer_bind_master_vol = {
9515 .ops = &snd_hda_bind_vol,
9516 .values = {
9517 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
9518 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
9519 0
9520 },
9521};
9522
Takashi Iwai889c4392007-08-23 18:56:52 +02009523/* mute/unmute internal speaker according to the hp jack and mute state */
9524static void alc268_acer_automute(struct hda_codec *codec, int force)
9525{
9526 struct alc_spec *spec = codec->spec;
9527 unsigned int mute;
9528
9529 if (force || !spec->sense_updated) {
9530 unsigned int present;
9531 present = snd_hda_codec_read(codec, 0x14, 0,
9532 AC_VERB_GET_PIN_SENSE, 0);
9533 spec->jack_present = (present & 0x80000000) != 0;
9534 spec->sense_updated = 1;
9535 }
9536 if (spec->jack_present)
9537 mute = HDA_AMP_MUTE; /* mute internal speaker */
9538 else /* unmute internal speaker if necessary */
9539 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
9540 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9541 HDA_AMP_MUTE, mute);
9542}
9543
9544
9545/* bind hp and internal speaker mute (with plug check) */
9546static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol,
9547 struct snd_ctl_elem_value *ucontrol)
9548{
9549 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9550 long *valp = ucontrol->value.integer.value;
9551 int change;
9552
9553 change = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
9554 HDA_AMP_MUTE,
9555 valp[0] ? 0 : HDA_AMP_MUTE);
9556 change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
9557 HDA_AMP_MUTE,
9558 valp[1] ? 0 : HDA_AMP_MUTE);
9559 if (change)
9560 alc268_acer_automute(codec, 0);
9561 return change;
9562}
Takashi Iwaid2738092007-08-16 14:59:45 +02009563
9564static struct snd_kcontrol_new alc268_acer_mixer[] = {
9565 /* output mixer control */
9566 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
9567 {
9568 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9569 .name = "Master Playback Switch",
9570 .info = snd_hda_mixer_amp_switch_info,
9571 .get = snd_hda_mixer_amp_switch_get,
9572 .put = alc268_acer_master_sw_put,
9573 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
9574 },
Takashi Iwai33bf17a2007-08-21 11:51:42 +02009575 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9576 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
9577 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Takashi Iwaid2738092007-08-16 14:59:45 +02009578 { }
9579};
9580
9581static struct hda_verb alc268_acer_verbs[] = {
9582 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9583 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9584
9585 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9586 { }
9587};
9588
9589/* unsolicited event for HP jack sensing */
9590static void alc268_toshiba_unsol_event(struct hda_codec *codec,
9591 unsigned int res)
9592{
Takashi Iwai889c4392007-08-23 18:56:52 +02009593 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +02009594 return;
9595 alc268_toshiba_automute(codec);
9596}
9597
9598static void alc268_acer_unsol_event(struct hda_codec *codec,
9599 unsigned int res)
9600{
Takashi Iwai889c4392007-08-23 18:56:52 +02009601 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +02009602 return;
9603 alc268_acer_automute(codec, 1);
9604}
9605
Takashi Iwai889c4392007-08-23 18:56:52 +02009606static void alc268_acer_init_hook(struct hda_codec *codec)
9607{
9608 alc268_acer_automute(codec, 1);
9609}
9610
Takashi Iwai3866f0b2008-01-15 12:37:42 +01009611static struct snd_kcontrol_new alc268_dell_mixer[] = {
9612 /* output mixer control */
9613 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
9614 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9615 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
9616 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9617 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9618 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
9619 { }
9620};
9621
9622static struct hda_verb alc268_dell_verbs[] = {
9623 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9624 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9625 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9626 { }
9627};
9628
9629/* mute/unmute internal speaker according to the hp jack and mute state */
9630static void alc268_dell_automute(struct hda_codec *codec)
9631{
9632 unsigned int present;
9633 unsigned int mute;
9634
9635 present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0);
9636 if (present & 0x80000000)
9637 mute = HDA_AMP_MUTE;
9638 else
9639 mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
9640 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9641 HDA_AMP_MUTE, mute);
9642}
9643
9644static void alc268_dell_unsol_event(struct hda_codec *codec,
9645 unsigned int res)
9646{
9647 if ((res >> 26) != ALC880_HP_EVENT)
9648 return;
9649 alc268_dell_automute(codec);
9650}
9651
9652#define alc268_dell_init_hook alc268_dell_automute
9653
Kailang Yanga361d842007-06-05 12:30:55 +02009654/*
9655 * generic initialization of ADC, input mixers and output mixers
9656 */
9657static struct hda_verb alc268_base_init_verbs[] = {
9658 /* Unmute DAC0-1 and set vol = 0 */
9659 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9660 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9661 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9662 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9663 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9664 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9665
9666 /*
9667 * Set up output mixers (0x0c - 0x0e)
9668 */
9669 /* set vol=0 to output mixers */
9670 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9671 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9672 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9673 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
9674
9675 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9676 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9677
9678 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
9679 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
9680 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
9681 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9682 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9683 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9684 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9685 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9686
9687 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9688 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9689 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9690 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9691 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9692 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9693 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9694 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9695
Jiang Zhea9b3aa82007-12-20 13:13:13 +01009696 /* Unmute Selector 23h,24h and set the default input to mic-in */
9697
9698 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
9699 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9700 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
9701 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yanga361d842007-06-05 12:30:55 +02009702
Kailang Yanga361d842007-06-05 12:30:55 +02009703 { }
9704};
9705
9706/*
9707 * generic initialization of ADC, input mixers and output mixers
9708 */
9709static struct hda_verb alc268_volume_init_verbs[] = {
9710 /* set output DAC */
9711 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9712 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9713 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9714 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9715
9716 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9717 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9718 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9719 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9720 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9721
9722 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9723 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9724 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9725 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9726 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9727
9728 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9729 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9730 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9731 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9732
9733 /* set PCBEEP vol = 0 */
9734 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, (0xb000 | (0x00 << 8))},
9735
9736 { }
9737};
9738
9739#define alc268_mux_enum_info alc_mux_enum_info
9740#define alc268_mux_enum_get alc_mux_enum_get
Takashi Iwaie1406342008-02-11 18:32:32 +01009741#define alc268_mux_enum_put alc_mux_enum_put
Kailang Yanga361d842007-06-05 12:30:55 +02009742
9743static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
9744 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
9745 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
9746 {
9747 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9748 /* The multiple "Capture Source" controls confuse alsamixer
9749 * So call somewhat different..
Kailang Yanga361d842007-06-05 12:30:55 +02009750 */
9751 /* .name = "Capture Source", */
9752 .name = "Input Source",
9753 .count = 1,
9754 .info = alc268_mux_enum_info,
9755 .get = alc268_mux_enum_get,
9756 .put = alc268_mux_enum_put,
9757 },
9758 { } /* end */
9759};
9760
9761static struct snd_kcontrol_new alc268_capture_mixer[] = {
9762 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
9763 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
9764 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
9765 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
9766 {
9767 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9768 /* The multiple "Capture Source" controls confuse alsamixer
9769 * So call somewhat different..
Kailang Yanga361d842007-06-05 12:30:55 +02009770 */
9771 /* .name = "Capture Source", */
9772 .name = "Input Source",
9773 .count = 2,
9774 .info = alc268_mux_enum_info,
9775 .get = alc268_mux_enum_get,
9776 .put = alc268_mux_enum_put,
9777 },
9778 { } /* end */
9779};
9780
9781static struct hda_input_mux alc268_capture_source = {
9782 .num_items = 4,
9783 .items = {
9784 { "Mic", 0x0 },
9785 { "Front Mic", 0x1 },
9786 { "Line", 0x2 },
9787 { "CD", 0x3 },
9788 },
9789};
9790
Jonathan Woithe86c53bd2008-01-08 12:33:19 +01009791#ifdef CONFIG_SND_DEBUG
9792static struct snd_kcontrol_new alc268_test_mixer[] = {
Jonathan Woithe86c53bd2008-01-08 12:33:19 +01009793 /* Volume widgets */
9794 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
9795 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
9796 HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
9797 HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
9798 HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
9799 HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
9800 HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
9801 HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
9802 HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
9803 HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
9804 HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
9805 HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
9806 HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
Takashi Iwaif0747ee2008-01-15 11:41:41 +01009807 /* The below appears problematic on some hardwares */
9808 /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
Jonathan Woithe86c53bd2008-01-08 12:33:19 +01009809 HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
9810 HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
9811 HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
9812 HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
9813
9814 /* Modes for retasking pin widgets */
9815 ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
9816 ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
9817 ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
9818 ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
9819
9820 /* Controls for GPIO pins, assuming they are configured as outputs */
9821 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
9822 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
9823 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
9824 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
9825
9826 /* Switches to allow the digital SPDIF output pin to be enabled.
9827 * The ALC268 does not have an SPDIF input.
9828 */
9829 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
9830
9831 /* A switch allowing EAPD to be enabled. Some laptops seem to use
9832 * this output to turn on an external amplifier.
9833 */
9834 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
9835 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
9836
9837 { } /* end */
9838};
9839#endif
9840
Kailang Yanga361d842007-06-05 12:30:55 +02009841/* create input playback/capture controls for the given pin */
9842static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
9843 const char *ctlname, int idx)
9844{
9845 char name[32];
9846 int err;
9847
9848 sprintf(name, "%s Playback Volume", ctlname);
9849 if (nid == 0x14) {
9850 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
9851 HDA_COMPOSE_AMP_VAL(0x02, 3, idx,
9852 HDA_OUTPUT));
9853 if (err < 0)
9854 return err;
9855 } else if (nid == 0x15) {
9856 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
9857 HDA_COMPOSE_AMP_VAL(0x03, 3, idx,
9858 HDA_OUTPUT));
9859 if (err < 0)
9860 return err;
9861 } else
9862 return -1;
9863 sprintf(name, "%s Playback Switch", ctlname);
9864 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
9865 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
9866 if (err < 0)
9867 return err;
9868 return 0;
9869}
9870
9871/* add playback controls from the parsed DAC table */
9872static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
9873 const struct auto_pin_cfg *cfg)
9874{
9875 hda_nid_t nid;
9876 int err;
9877
9878 spec->multiout.num_dacs = 2; /* only use one dac */
9879 spec->multiout.dac_nids = spec->private_dac_nids;
9880 spec->multiout.dac_nids[0] = 2;
9881 spec->multiout.dac_nids[1] = 3;
9882
9883 nid = cfg->line_out_pins[0];
9884 if (nid)
9885 alc268_new_analog_output(spec, nid, "Front", 0);
9886
9887 nid = cfg->speaker_pins[0];
9888 if (nid == 0x1d) {
9889 err = add_control(spec, ALC_CTL_WIDGET_VOL,
9890 "Speaker Playback Volume",
9891 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
9892 if (err < 0)
9893 return err;
9894 }
9895 nid = cfg->hp_pins[0];
9896 if (nid)
9897 alc268_new_analog_output(spec, nid, "Headphone", 0);
9898
9899 nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
9900 if (nid == 0x16) {
9901 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9902 "Mono Playback Switch",
9903 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_INPUT));
9904 if (err < 0)
9905 return err;
9906 }
9907 return 0;
9908}
9909
9910/* create playback/capture controls for input pins */
9911static int alc268_auto_create_analog_input_ctls(struct alc_spec *spec,
9912 const struct auto_pin_cfg *cfg)
9913{
9914 struct hda_input_mux *imux = &spec->private_imux;
9915 int i, idx1;
9916
9917 for (i = 0; i < AUTO_PIN_LAST; i++) {
9918 switch(cfg->input_pins[i]) {
9919 case 0x18:
9920 idx1 = 0; /* Mic 1 */
9921 break;
9922 case 0x19:
9923 idx1 = 1; /* Mic 2 */
9924 break;
9925 case 0x1a:
9926 idx1 = 2; /* Line In */
9927 break;
9928 case 0x1c:
9929 idx1 = 3; /* CD */
9930 break;
9931 default:
9932 continue;
9933 }
9934 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
9935 imux->items[imux->num_items].index = idx1;
9936 imux->num_items++;
9937 }
9938 return 0;
9939}
9940
9941static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
9942{
9943 struct alc_spec *spec = codec->spec;
9944 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
9945 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
9946 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
9947 unsigned int dac_vol1, dac_vol2;
9948
9949 if (speaker_nid) {
9950 snd_hda_codec_write(codec, speaker_nid, 0,
9951 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
9952 snd_hda_codec_write(codec, 0x0f, 0,
9953 AC_VERB_SET_AMP_GAIN_MUTE,
9954 AMP_IN_UNMUTE(1));
9955 snd_hda_codec_write(codec, 0x10, 0,
9956 AC_VERB_SET_AMP_GAIN_MUTE,
9957 AMP_IN_UNMUTE(1));
9958 } else {
9959 snd_hda_codec_write(codec, 0x0f, 0,
9960 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
9961 snd_hda_codec_write(codec, 0x10, 0,
9962 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
9963 }
9964
9965 dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */
9966 if (line_nid == 0x14)
9967 dac_vol2 = AMP_OUT_ZERO;
9968 else if (line_nid == 0x15)
9969 dac_vol1 = AMP_OUT_ZERO;
9970 if (hp_nid == 0x14)
9971 dac_vol2 = AMP_OUT_ZERO;
9972 else if (hp_nid == 0x15)
9973 dac_vol1 = AMP_OUT_ZERO;
9974 if (line_nid != 0x16 || hp_nid != 0x16 ||
9975 spec->autocfg.line_out_pins[1] != 0x16 ||
9976 spec->autocfg.line_out_pins[2] != 0x16)
9977 dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
9978
9979 snd_hda_codec_write(codec, 0x02, 0,
9980 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
9981 snd_hda_codec_write(codec, 0x03, 0,
9982 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
9983}
9984
9985/* pcm configuration: identiacal with ALC880 */
9986#define alc268_pcm_analog_playback alc880_pcm_analog_playback
9987#define alc268_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +01009988#define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Kailang Yanga361d842007-06-05 12:30:55 +02009989#define alc268_pcm_digital_playback alc880_pcm_digital_playback
9990
9991/*
9992 * BIOS auto configuration
9993 */
9994static int alc268_parse_auto_config(struct hda_codec *codec)
9995{
9996 struct alc_spec *spec = codec->spec;
9997 int err;
9998 static hda_nid_t alc268_ignore[] = { 0 };
9999
10000 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
10001 alc268_ignore);
10002 if (err < 0)
10003 return err;
10004 if (!spec->autocfg.line_outs)
10005 return 0; /* can't find valid BIOS pin config */
10006
10007 err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
10008 if (err < 0)
10009 return err;
10010 err = alc268_auto_create_analog_input_ctls(spec, &spec->autocfg);
10011 if (err < 0)
10012 return err;
10013
10014 spec->multiout.max_channels = 2;
10015
10016 /* digital only support output */
10017 if (spec->autocfg.dig_out_pin)
10018 spec->multiout.dig_out_nid = ALC268_DIGOUT_NID;
10019
10020 if (spec->kctl_alloc)
10021 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
10022
10023 spec->init_verbs[spec->num_init_verbs++] = alc268_volume_init_verbs;
10024 spec->num_mux_defs = 1;
10025 spec->input_mux = &spec->private_imux;
10026
Takashi Iwai776e1842007-08-29 15:07:11 +020010027 err = alc_auto_add_mic_boost(codec);
10028 if (err < 0)
10029 return err;
10030
Kailang Yanga361d842007-06-05 12:30:55 +020010031 return 1;
10032}
10033
10034#define alc268_auto_init_multi_out alc882_auto_init_multi_out
10035#define alc268_auto_init_hp_out alc882_auto_init_hp_out
10036#define alc268_auto_init_analog_input alc882_auto_init_analog_input
10037
10038/* init callback for auto-configuration model -- overriding the default init */
10039static void alc268_auto_init(struct hda_codec *codec)
10040{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010041 struct alc_spec *spec = codec->spec;
Kailang Yanga361d842007-06-05 12:30:55 +020010042 alc268_auto_init_multi_out(codec);
10043 alc268_auto_init_hp_out(codec);
10044 alc268_auto_init_mono_speaker_out(codec);
10045 alc268_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010046 if (spec->unsol_event)
10047 alc_sku_automute(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020010048}
10049
10050/*
10051 * configuration and preset
10052 */
10053static const char *alc268_models[ALC268_MODEL_LAST] = {
10054 [ALC268_3ST] = "3stack",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020010055 [ALC268_TOSHIBA] = "toshiba",
Takashi Iwaid2738092007-08-16 14:59:45 +020010056 [ALC268_ACER] = "acer",
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010057 [ALC268_DELL] = "dell",
Mirco Tischlerf12462c2008-02-04 12:33:59 +010010058 [ALC268_ZEPTO] = "zepto",
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010010059#ifdef CONFIG_SND_DEBUG
10060 [ALC268_TEST] = "test",
10061#endif
Kailang Yanga361d842007-06-05 12:30:55 +020010062 [ALC268_AUTO] = "auto",
10063};
10064
10065static struct snd_pci_quirk alc268_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010066 SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
Andy Shevchenkodafc8352008-01-25 11:53:50 +010010067 SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010068 SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
Andy Shevchenko29a52c22008-01-24 17:29:00 +010010069 SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010070 SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010071 SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA),
Kailang Yanga361d842007-06-05 12:30:55 +020010072 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
Kailang Yangd1a991a2007-08-15 16:21:59 +020010073 SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA),
Takashi Iwai8e7f00f2007-09-07 10:58:58 +020010074 SND_PCI_QUIRK(0x1179, 0xff50, "TOSHIBA A305", ALC268_TOSHIBA),
Takashi Iwaib875bf32007-09-06 15:00:27 +020010075 SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
Mirco Tischlerf12462c2008-02-04 12:33:59 +010010076 SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
Kailang Yanga361d842007-06-05 12:30:55 +020010077 {}
10078};
10079
10080static struct alc_config_preset alc268_presets[] = {
10081 [ALC268_3ST] = {
10082 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer },
10083 .init_verbs = { alc268_base_init_verbs },
10084 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
10085 .dac_nids = alc268_dac_nids,
10086 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
10087 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010010088 .capsrc_nids = alc268_capsrc_nids,
Kailang Yanga361d842007-06-05 12:30:55 +020010089 .hp_nid = 0x03,
10090 .dig_out_nid = ALC268_DIGOUT_NID,
10091 .num_channel_mode = ARRAY_SIZE(alc268_modes),
10092 .channel_mode = alc268_modes,
10093 .input_mux = &alc268_capture_source,
10094 },
Kailang Yangd1a991a2007-08-15 16:21:59 +020010095 [ALC268_TOSHIBA] = {
10096 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020010097 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
10098 alc268_toshiba_verbs },
Kailang Yangd1a991a2007-08-15 16:21:59 +020010099 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
10100 .dac_nids = alc268_dac_nids,
10101 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
10102 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010010103 .capsrc_nids = alc268_capsrc_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020010104 .hp_nid = 0x03,
10105 .num_channel_mode = ARRAY_SIZE(alc268_modes),
10106 .channel_mode = alc268_modes,
10107 .input_mux = &alc268_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020010108 .unsol_event = alc268_toshiba_unsol_event,
10109 .init_hook = alc268_toshiba_automute,
10110 },
10111 [ALC268_ACER] = {
10112 .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer },
10113 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
10114 alc268_acer_verbs },
10115 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
10116 .dac_nids = alc268_dac_nids,
10117 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
10118 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010010119 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwaid2738092007-08-16 14:59:45 +020010120 .hp_nid = 0x02,
10121 .num_channel_mode = ARRAY_SIZE(alc268_modes),
10122 .channel_mode = alc268_modes,
10123 .input_mux = &alc268_capture_source,
10124 .unsol_event = alc268_acer_unsol_event,
Takashi Iwai889c4392007-08-23 18:56:52 +020010125 .init_hook = alc268_acer_init_hook,
Kailang Yangd1a991a2007-08-15 16:21:59 +020010126 },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010127 [ALC268_DELL] = {
10128 .mixers = { alc268_dell_mixer },
10129 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
10130 alc268_dell_verbs },
10131 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
10132 .dac_nids = alc268_dac_nids,
10133 .hp_nid = 0x02,
10134 .num_channel_mode = ARRAY_SIZE(alc268_modes),
10135 .channel_mode = alc268_modes,
10136 .unsol_event = alc268_dell_unsol_event,
10137 .init_hook = alc268_dell_init_hook,
10138 .input_mux = &alc268_capture_source,
10139 },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010010140 [ALC268_ZEPTO] = {
10141 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer },
10142 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
10143 alc268_toshiba_verbs },
10144 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
10145 .dac_nids = alc268_dac_nids,
10146 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
10147 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010010148 .capsrc_nids = alc268_capsrc_nids,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010010149 .hp_nid = 0x03,
10150 .dig_out_nid = ALC268_DIGOUT_NID,
10151 .num_channel_mode = ARRAY_SIZE(alc268_modes),
10152 .channel_mode = alc268_modes,
10153 .input_mux = &alc268_capture_source,
10154 .unsol_event = alc268_toshiba_unsol_event,
10155 .init_hook = alc268_toshiba_automute
10156 },
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010010157#ifdef CONFIG_SND_DEBUG
10158 [ALC268_TEST] = {
10159 .mixers = { alc268_test_mixer, alc268_capture_mixer },
10160 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
10161 alc268_volume_init_verbs },
10162 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
10163 .dac_nids = alc268_dac_nids,
10164 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
10165 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010010166 .capsrc_nids = alc268_capsrc_nids,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010010167 .hp_nid = 0x03,
10168 .dig_out_nid = ALC268_DIGOUT_NID,
10169 .num_channel_mode = ARRAY_SIZE(alc268_modes),
10170 .channel_mode = alc268_modes,
10171 .input_mux = &alc268_capture_source,
10172 },
10173#endif
Kailang Yanga361d842007-06-05 12:30:55 +020010174};
10175
10176static int patch_alc268(struct hda_codec *codec)
10177{
10178 struct alc_spec *spec;
10179 int board_config;
10180 int err;
10181
10182 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
10183 if (spec == NULL)
10184 return -ENOMEM;
10185
10186 codec->spec = spec;
10187
10188 board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
10189 alc268_models,
10190 alc268_cfg_tbl);
10191
10192 if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
10193 printk(KERN_INFO "hda_codec: Unknown model for ALC268, "
10194 "trying auto-probe from BIOS...\n");
10195 board_config = ALC268_AUTO;
10196 }
10197
10198 if (board_config == ALC268_AUTO) {
10199 /* automatic parse from the BIOS config */
10200 err = alc268_parse_auto_config(codec);
10201 if (err < 0) {
10202 alc_free(codec);
10203 return err;
10204 } else if (!err) {
10205 printk(KERN_INFO
10206 "hda_codec: Cannot set up configuration "
10207 "from BIOS. Using base mode...\n");
10208 board_config = ALC268_3ST;
10209 }
10210 }
10211
10212 if (board_config != ALC268_AUTO)
10213 setup_preset(spec, &alc268_presets[board_config]);
10214
10215 spec->stream_name_analog = "ALC268 Analog";
10216 spec->stream_analog_playback = &alc268_pcm_analog_playback;
10217 spec->stream_analog_capture = &alc268_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +010010218 spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
Kailang Yanga361d842007-06-05 12:30:55 +020010219
10220 spec->stream_name_digital = "ALC268 Digital";
10221 spec->stream_digital_playback = &alc268_pcm_digital_playback;
10222
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010223 if (!spec->adc_nids && spec->input_mux) {
10224 /* check whether NID 0x07 is valid */
10225 unsigned int wcap = get_wcaps(codec, 0x07);
Kailang Yanga361d842007-06-05 12:30:55 +020010226
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010227 /* get type */
10228 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
10229 if (wcap != AC_WID_AUD_IN) {
10230 spec->adc_nids = alc268_adc_nids_alt;
10231 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
10232 spec->mixers[spec->num_mixers] =
Kailang Yanga361d842007-06-05 12:30:55 +020010233 alc268_capture_alt_mixer;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010234 spec->num_mixers++;
10235 } else {
10236 spec->adc_nids = alc268_adc_nids;
10237 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
10238 spec->mixers[spec->num_mixers] =
10239 alc268_capture_mixer;
10240 spec->num_mixers++;
Kailang Yanga361d842007-06-05 12:30:55 +020010241 }
Takashi Iwaie1406342008-02-11 18:32:32 +010010242 spec->capsrc_nids = alc268_capsrc_nids;
Kailang Yanga361d842007-06-05 12:30:55 +020010243 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010010244
10245 spec->vmaster_nid = 0x02;
10246
Kailang Yanga361d842007-06-05 12:30:55 +020010247 codec->patch_ops = alc_patch_ops;
10248 if (board_config == ALC268_AUTO)
10249 spec->init_hook = alc268_auto_init;
10250
10251 return 0;
10252}
10253
10254/*
Kailang Yangf6a92242007-12-13 16:52:54 +010010255 * ALC269 channel source setting (2 channel)
10256 */
10257#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID
10258
10259#define alc269_dac_nids alc260_dac_nids
10260
10261static hda_nid_t alc269_adc_nids[1] = {
10262 /* ADC1 */
10263 0x07,
10264};
10265
10266#define alc269_modes alc260_modes
10267#define alc269_capture_source alc880_lg_lw_capture_source
10268
10269static struct snd_kcontrol_new alc269_base_mixer[] = {
10270 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
10271 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
10272 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
10273 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
10274 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10275 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10276 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10277 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10278 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
10279 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
10280 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10281 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
10282 { } /* end */
10283};
10284
10285/* capture mixer elements */
10286static struct snd_kcontrol_new alc269_capture_mixer[] = {
10287 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
10288 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
10289 {
10290 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10291 /* The multiple "Capture Source" controls confuse alsamixer
10292 * So call somewhat different..
Kailang Yangf6a92242007-12-13 16:52:54 +010010293 */
10294 /* .name = "Capture Source", */
10295 .name = "Input Source",
10296 .count = 1,
10297 .info = alc_mux_enum_info,
10298 .get = alc_mux_enum_get,
10299 .put = alc_mux_enum_put,
10300 },
10301 { } /* end */
10302};
10303
10304/*
10305 * generic initialization of ADC, input mixers and output mixers
10306 */
10307static struct hda_verb alc269_init_verbs[] = {
10308 /*
10309 * Unmute ADC0 and set the default input to mic-in
10310 */
10311 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10312
10313 /* Mute input amps (PCBeep, Line In, Mic 1 & Mic 2) of the
10314 * analog-loopback mixer widget
10315 * Note: PASD motherboards uses the Line In 2 as the input for
10316 * front panel mic (mic 2)
10317 */
10318 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
10319 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10320 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10321 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10322 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10323 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
10324
10325 /*
10326 * Set up output mixers (0x0c - 0x0e)
10327 */
10328 /* set vol=0 to output mixers */
10329 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10330 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10331
10332 /* set up input amps for analog loopback */
10333 /* Amp Indices: DAC = 0, mixer = 1 */
10334 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10335 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10336 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10337 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10338 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10339 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10340
10341 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10342 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10343 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10344 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
10345 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
10346 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
10347 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
10348
10349 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10350 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10351 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10352 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10353 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10354 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10355 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10356
10357 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
10358 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10359
10360 /* FIXME: use matrix-type input source selection */
10361 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
10362 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
10363 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10364 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10365 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10366 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10367
10368 /* set EAPD */
10369 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
10370 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
10371 { }
10372};
10373
10374/* add playback controls from the parsed DAC table */
10375static int alc269_auto_create_multi_out_ctls(struct alc_spec *spec,
10376 const struct auto_pin_cfg *cfg)
10377{
10378 hda_nid_t nid;
10379 int err;
10380
10381 spec->multiout.num_dacs = 1; /* only use one dac */
10382 spec->multiout.dac_nids = spec->private_dac_nids;
10383 spec->multiout.dac_nids[0] = 2;
10384
10385 nid = cfg->line_out_pins[0];
10386 if (nid) {
10387 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10388 "Front Playback Volume",
10389 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT));
10390 if (err < 0)
10391 return err;
10392 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10393 "Front Playback Switch",
10394 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
10395 if (err < 0)
10396 return err;
10397 }
10398
10399 nid = cfg->speaker_pins[0];
10400 if (nid) {
10401 if (!cfg->line_out_pins[0]) {
10402 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10403 "Speaker Playback Volume",
10404 HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
10405 HDA_OUTPUT));
10406 if (err < 0)
10407 return err;
10408 }
10409 if (nid == 0x16) {
10410 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10411 "Speaker Playback Switch",
10412 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
10413 HDA_OUTPUT));
10414 if (err < 0)
10415 return err;
10416 } else {
10417 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10418 "Speaker Playback Switch",
10419 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
10420 HDA_OUTPUT));
10421 if (err < 0)
10422 return err;
10423 }
10424 }
10425 nid = cfg->hp_pins[0];
10426 if (nid) {
10427 /* spec->multiout.hp_nid = 2; */
10428 if (!cfg->line_out_pins[0] && !cfg->speaker_pins[0]) {
10429 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10430 "Headphone Playback Volume",
10431 HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
10432 HDA_OUTPUT));
10433 if (err < 0)
10434 return err;
10435 }
10436 if (nid == 0x16) {
10437 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10438 "Headphone Playback Switch",
10439 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
10440 HDA_OUTPUT));
10441 if (err < 0)
10442 return err;
10443 } else {
10444 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10445 "Headphone Playback Switch",
10446 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
10447 HDA_OUTPUT));
10448 if (err < 0)
10449 return err;
10450 }
10451 }
10452 return 0;
10453}
10454
10455#define alc269_auto_create_analog_input_ctls \
10456 alc880_auto_create_analog_input_ctls
10457
10458#ifdef CONFIG_SND_HDA_POWER_SAVE
10459#define alc269_loopbacks alc880_loopbacks
10460#endif
10461
10462/* pcm configuration: identiacal with ALC880 */
10463#define alc269_pcm_analog_playback alc880_pcm_analog_playback
10464#define alc269_pcm_analog_capture alc880_pcm_analog_capture
10465#define alc269_pcm_digital_playback alc880_pcm_digital_playback
10466#define alc269_pcm_digital_capture alc880_pcm_digital_capture
10467
10468/*
10469 * BIOS auto configuration
10470 */
10471static int alc269_parse_auto_config(struct hda_codec *codec)
10472{
10473 struct alc_spec *spec = codec->spec;
10474 int err;
10475 static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
10476
10477 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
10478 alc269_ignore);
10479 if (err < 0)
10480 return err;
10481
10482 err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
10483 if (err < 0)
10484 return err;
10485 err = alc269_auto_create_analog_input_ctls(spec, &spec->autocfg);
10486 if (err < 0)
10487 return err;
10488
10489 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
10490
10491 if (spec->autocfg.dig_out_pin)
10492 spec->multiout.dig_out_nid = ALC269_DIGOUT_NID;
10493
10494 if (spec->kctl_alloc)
10495 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
10496
10497 spec->init_verbs[spec->num_init_verbs++] = alc269_init_verbs;
10498 spec->num_mux_defs = 1;
10499 spec->input_mux = &spec->private_imux;
10500
10501 err = alc_auto_add_mic_boost(codec);
10502 if (err < 0)
10503 return err;
10504
10505 return 1;
10506}
10507
10508#define alc269_auto_init_multi_out alc882_auto_init_multi_out
10509#define alc269_auto_init_hp_out alc882_auto_init_hp_out
10510#define alc269_auto_init_analog_input alc882_auto_init_analog_input
10511
10512
10513/* init callback for auto-configuration model -- overriding the default init */
10514static void alc269_auto_init(struct hda_codec *codec)
10515{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010516 struct alc_spec *spec = codec->spec;
Kailang Yangf6a92242007-12-13 16:52:54 +010010517 alc269_auto_init_multi_out(codec);
10518 alc269_auto_init_hp_out(codec);
10519 alc269_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010520 if (spec->unsol_event)
10521 alc_sku_automute(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010010522}
10523
10524/*
10525 * configuration and preset
10526 */
10527static const char *alc269_models[ALC269_MODEL_LAST] = {
10528 [ALC269_BASIC] = "basic",
10529};
10530
10531static struct snd_pci_quirk alc269_cfg_tbl[] = {
10532 {}
10533};
10534
10535static struct alc_config_preset alc269_presets[] = {
10536 [ALC269_BASIC] = {
10537 .mixers = { alc269_base_mixer },
10538 .init_verbs = { alc269_init_verbs },
10539 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
10540 .dac_nids = alc269_dac_nids,
10541 .hp_nid = 0x03,
10542 .num_channel_mode = ARRAY_SIZE(alc269_modes),
10543 .channel_mode = alc269_modes,
10544 .input_mux = &alc269_capture_source,
10545 },
10546};
10547
10548static int patch_alc269(struct hda_codec *codec)
10549{
10550 struct alc_spec *spec;
10551 int board_config;
10552 int err;
10553
10554 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
10555 if (spec == NULL)
10556 return -ENOMEM;
10557
10558 codec->spec = spec;
10559
10560 board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
10561 alc269_models,
10562 alc269_cfg_tbl);
10563
10564 if (board_config < 0) {
10565 printk(KERN_INFO "hda_codec: Unknown model for ALC269, "
10566 "trying auto-probe from BIOS...\n");
10567 board_config = ALC269_AUTO;
10568 }
10569
10570 if (board_config == ALC269_AUTO) {
10571 /* automatic parse from the BIOS config */
10572 err = alc269_parse_auto_config(codec);
10573 if (err < 0) {
10574 alc_free(codec);
10575 return err;
10576 } else if (!err) {
10577 printk(KERN_INFO
10578 "hda_codec: Cannot set up configuration "
10579 "from BIOS. Using base mode...\n");
10580 board_config = ALC269_BASIC;
10581 }
10582 }
10583
10584 if (board_config != ALC269_AUTO)
10585 setup_preset(spec, &alc269_presets[board_config]);
10586
10587 spec->stream_name_analog = "ALC269 Analog";
10588 spec->stream_analog_playback = &alc269_pcm_analog_playback;
10589 spec->stream_analog_capture = &alc269_pcm_analog_capture;
10590
10591 spec->stream_name_digital = "ALC269 Digital";
10592 spec->stream_digital_playback = &alc269_pcm_digital_playback;
10593 spec->stream_digital_capture = &alc269_pcm_digital_capture;
10594
10595 spec->adc_nids = alc269_adc_nids;
10596 spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
10597 spec->mixers[spec->num_mixers] = alc269_capture_mixer;
10598 spec->num_mixers++;
10599
10600 codec->patch_ops = alc_patch_ops;
10601 if (board_config == ALC269_AUTO)
10602 spec->init_hook = alc269_auto_init;
10603#ifdef CONFIG_SND_HDA_POWER_SAVE
10604 if (!spec->loopback.amplist)
10605 spec->loopback.amplist = alc269_loopbacks;
10606#endif
10607
10608 return 0;
10609}
10610
10611/*
Kailang Yangdf694da2005-12-05 19:42:22 +010010612 * ALC861 channel source setting (2/6 channel selection for 3-stack)
10613 */
10614
10615/*
10616 * set the path ways for 2 channel output
10617 * need to set the codec line out and mic 1 pin widgets to inputs
10618 */
10619static struct hda_verb alc861_threestack_ch2_init[] = {
10620 /* set pin widget 1Ah (line in) for input */
10621 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010622 /* set pin widget 18h (mic1/2) for input, for mic also enable
10623 * the vref
10624 */
Kailang Yangdf694da2005-12-05 19:42:22 +010010625 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10626
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010627 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
10628#if 0
10629 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
10630 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
10631#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010010632 { } /* end */
10633};
10634/*
10635 * 6ch mode
10636 * need to set the codec line out and mic 1 pin widgets to outputs
10637 */
10638static struct hda_verb alc861_threestack_ch6_init[] = {
10639 /* set pin widget 1Ah (line in) for output (Back Surround)*/
10640 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10641 /* set pin widget 18h (mic1) for output (CLFE)*/
10642 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10643
10644 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010645 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010010646
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010647 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
10648#if 0
10649 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
10650 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
10651#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010010652 { } /* end */
10653};
10654
10655static struct hda_channel_mode alc861_threestack_modes[2] = {
10656 { 2, alc861_threestack_ch2_init },
10657 { 6, alc861_threestack_ch6_init },
10658};
Takashi Iwai22309c32006-08-09 16:57:28 +020010659/* Set mic1 as input and unmute the mixer */
10660static struct hda_verb alc861_uniwill_m31_ch2_init[] = {
10661 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10662 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
10663 { } /* end */
10664};
10665/* Set mic1 as output and mute mixer */
10666static struct hda_verb alc861_uniwill_m31_ch4_init[] = {
10667 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10668 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
10669 { } /* end */
10670};
10671
10672static struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
10673 { 2, alc861_uniwill_m31_ch2_init },
10674 { 4, alc861_uniwill_m31_ch4_init },
10675};
Kailang Yangdf694da2005-12-05 19:42:22 +010010676
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020010677/* Set mic1 and line-in as input and unmute the mixer */
10678static struct hda_verb alc861_asus_ch2_init[] = {
10679 /* set pin widget 1Ah (line in) for input */
10680 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010681 /* set pin widget 18h (mic1/2) for input, for mic also enable
10682 * the vref
10683 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020010684 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10685
10686 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
10687#if 0
10688 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
10689 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
10690#endif
10691 { } /* end */
10692};
10693/* Set mic1 nad line-in as output and mute mixer */
10694static struct hda_verb alc861_asus_ch6_init[] = {
10695 /* set pin widget 1Ah (line in) for output (Back Surround)*/
10696 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10697 /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
10698 /* set pin widget 18h (mic1) for output (CLFE)*/
10699 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10700 /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
10701 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
10702 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
10703
10704 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
10705#if 0
10706 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
10707 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
10708#endif
10709 { } /* end */
10710};
10711
10712static struct hda_channel_mode alc861_asus_modes[2] = {
10713 { 2, alc861_asus_ch2_init },
10714 { 6, alc861_asus_ch6_init },
10715};
10716
Kailang Yangdf694da2005-12-05 19:42:22 +010010717/* patch-ALC861 */
10718
10719static struct snd_kcontrol_new alc861_base_mixer[] = {
10720 /* output mixer control */
10721 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
10722 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
10723 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
10724 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
10725 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
10726
10727 /*Input mixer control */
10728 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
10729 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
10730 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
10731 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
10732 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
10733 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
10734 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
10735 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
10736 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
10737 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010738
Kailang Yangdf694da2005-12-05 19:42:22 +010010739 /* Capture mixer control */
10740 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
10741 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
10742 {
10743 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10744 .name = "Capture Source",
10745 .count = 1,
10746 .info = alc_mux_enum_info,
10747 .get = alc_mux_enum_get,
10748 .put = alc_mux_enum_put,
10749 },
10750 { } /* end */
10751};
10752
10753static struct snd_kcontrol_new alc861_3ST_mixer[] = {
10754 /* output mixer control */
10755 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
10756 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
10757 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
10758 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
10759 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
10760
10761 /* Input mixer control */
10762 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
10763 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
10764 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
10765 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
10766 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
10767 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
10768 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
10769 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
10770 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
10771 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010772
Kailang Yangdf694da2005-12-05 19:42:22 +010010773 /* Capture mixer control */
10774 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
10775 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
10776 {
10777 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10778 .name = "Capture Source",
10779 .count = 1,
10780 .info = alc_mux_enum_info,
10781 .get = alc_mux_enum_get,
10782 .put = alc_mux_enum_put,
10783 },
10784 {
10785 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10786 .name = "Channel Mode",
10787 .info = alc_ch_mode_info,
10788 .get = alc_ch_mode_get,
10789 .put = alc_ch_mode_put,
10790 .private_value = ARRAY_SIZE(alc861_threestack_modes),
10791 },
10792 { } /* end */
Tobin Davisa53d1ae2006-10-17 12:00:28 +020010793};
10794
Takashi Iwaid1d985f2006-11-23 19:27:12 +010010795static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020010796 /* output mixer control */
10797 HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
10798 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
10799 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
10800
10801 /*Capture mixer control */
10802 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
10803 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
10804 {
10805 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10806 .name = "Capture Source",
10807 .count = 1,
10808 .info = alc_mux_enum_info,
10809 .get = alc_mux_enum_get,
10810 .put = alc_mux_enum_put,
10811 },
10812
10813 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010814};
Tobin Davisa53d1ae2006-10-17 12:00:28 +020010815
Takashi Iwai22309c32006-08-09 16:57:28 +020010816static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
10817 /* output mixer control */
10818 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
10819 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
10820 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
10821 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
10822 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
10823
10824 /* Input mixer control */
10825 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
10826 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
10827 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
10828 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
10829 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
10830 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
10831 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
10832 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
10833 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
10834 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010835
Takashi Iwai22309c32006-08-09 16:57:28 +020010836 /* Capture mixer control */
10837 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
10838 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
10839 {
10840 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10841 .name = "Capture Source",
10842 .count = 1,
10843 .info = alc_mux_enum_info,
10844 .get = alc_mux_enum_get,
10845 .put = alc_mux_enum_put,
10846 },
10847 {
10848 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10849 .name = "Channel Mode",
10850 .info = alc_ch_mode_info,
10851 .get = alc_ch_mode_get,
10852 .put = alc_ch_mode_put,
10853 .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
10854 },
10855 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010856};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020010857
10858static struct snd_kcontrol_new alc861_asus_mixer[] = {
10859 /* output mixer control */
10860 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
10861 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
10862 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
10863 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
10864 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
10865
10866 /* Input mixer control */
10867 HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
10868 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10869 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
10870 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
10871 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
10872 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
10873 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
10874 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
10875 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010876 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
10877
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020010878 /* Capture mixer control */
10879 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
10880 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
10881 {
10882 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10883 .name = "Capture Source",
10884 .count = 1,
10885 .info = alc_mux_enum_info,
10886 .get = alc_mux_enum_get,
10887 .put = alc_mux_enum_put,
10888 },
10889 {
10890 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10891 .name = "Channel Mode",
10892 .info = alc_ch_mode_info,
10893 .get = alc_ch_mode_get,
10894 .put = alc_ch_mode_put,
10895 .private_value = ARRAY_SIZE(alc861_asus_modes),
10896 },
10897 { }
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010010898};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020010899
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010010900/* additional mixer */
Takashi Iwaid1d985f2006-11-23 19:27:12 +010010901static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010010902 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
10903 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
10904 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x23, 0x0, HDA_OUTPUT),
10905 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x23, 0x0, HDA_OUTPUT),
10906 { }
10907};
10908
Kailang Yangdf694da2005-12-05 19:42:22 +010010909/*
10910 * generic initialization of ADC, input mixers and output mixers
10911 */
10912static struct hda_verb alc861_base_init_verbs[] = {
10913 /*
10914 * Unmute ADC0 and set the default input to mic-in
10915 */
10916 /* port-A for surround (rear panel) */
10917 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10918 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
10919 /* port-B for mic-in (rear panel) with vref */
10920 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10921 /* port-C for line-in (rear panel) */
10922 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
10923 /* port-D for Front */
10924 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10925 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
10926 /* port-E for HP out (front panel) */
10927 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
10928 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010010929 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010010930 /* port-F for mic-in (front panel) with vref */
10931 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10932 /* port-G for CLFE (rear panel) */
10933 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10934 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
10935 /* port-H for side (rear panel) */
10936 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10937 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
10938 /* CD-in */
10939 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
10940 /* route front mic to ADC1*/
10941 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
10942 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10943
10944 /* Unmute DAC0~3 & spdif out*/
10945 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10946 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10947 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10948 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10949 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10950
10951 /* Unmute Mixer 14 (mic) 1c (Line in)*/
10952 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10953 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10954 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10955 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10956
10957 /* Unmute Stereo Mixer 15 */
10958 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10959 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10960 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010961 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010010962
10963 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10964 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10965 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10966 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10967 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10968 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10969 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10970 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010971 /* hp used DAC 3 (Front) */
10972 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010010973 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
10974
10975 { }
10976};
10977
10978static struct hda_verb alc861_threestack_init_verbs[] = {
10979 /*
10980 * Unmute ADC0 and set the default input to mic-in
10981 */
10982 /* port-A for surround (rear panel) */
10983 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
10984 /* port-B for mic-in (rear panel) with vref */
10985 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10986 /* port-C for line-in (rear panel) */
10987 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
10988 /* port-D for Front */
10989 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
10990 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
10991 /* port-E for HP out (front panel) */
10992 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
10993 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010010994 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010010995 /* port-F for mic-in (front panel) with vref */
10996 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
10997 /* port-G for CLFE (rear panel) */
10998 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
10999 /* port-H for side (rear panel) */
11000 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
11001 /* CD-in */
11002 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
11003 /* route front mic to ADC1*/
11004 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11005 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11006 /* Unmute DAC0~3 & spdif out*/
11007 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11008 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11009 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11010 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11011 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11012
11013 /* Unmute Mixer 14 (mic) 1c (Line in)*/
11014 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11015 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11016 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11017 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11018
11019 /* Unmute Stereo Mixer 15 */
11020 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11021 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11022 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011023 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010011024
11025 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11026 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11027 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11028 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11029 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11030 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11031 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11032 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011033 /* hp used DAC 3 (Front) */
11034 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011035 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
11036 { }
11037};
Takashi Iwai22309c32006-08-09 16:57:28 +020011038
11039static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
11040 /*
11041 * Unmute ADC0 and set the default input to mic-in
11042 */
11043 /* port-A for surround (rear panel) */
11044 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
11045 /* port-B for mic-in (rear panel) with vref */
11046 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
11047 /* port-C for line-in (rear panel) */
11048 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
11049 /* port-D for Front */
11050 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11051 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
11052 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011053 /* this has to be set to VREF80 */
11054 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Takashi Iwai22309c32006-08-09 16:57:28 +020011055 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010011056 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai22309c32006-08-09 16:57:28 +020011057 /* port-F for mic-in (front panel) with vref */
11058 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
11059 /* port-G for CLFE (rear panel) */
11060 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
11061 /* port-H for side (rear panel) */
11062 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
11063 /* CD-in */
11064 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
11065 /* route front mic to ADC1*/
11066 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11067 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11068 /* Unmute DAC0~3 & spdif out*/
11069 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11070 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11071 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11072 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11073 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11074
11075 /* Unmute Mixer 14 (mic) 1c (Line in)*/
11076 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11077 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11078 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11079 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11080
11081 /* Unmute Stereo Mixer 15 */
11082 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11083 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11084 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011085 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Takashi Iwai22309c32006-08-09 16:57:28 +020011086
11087 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11088 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11089 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11090 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11091 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11092 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11093 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11094 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011095 /* hp used DAC 3 (Front) */
11096 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Takashi Iwai22309c32006-08-09 16:57:28 +020011097 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
11098 { }
11099};
11100
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011101static struct hda_verb alc861_asus_init_verbs[] = {
11102 /*
11103 * Unmute ADC0 and set the default input to mic-in
11104 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011105 /* port-A for surround (rear panel)
11106 * according to codec#0 this is the HP jack
11107 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011108 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
11109 /* route front PCM to HP */
11110 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
11111 /* port-B for mic-in (rear panel) with vref */
11112 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
11113 /* port-C for line-in (rear panel) */
11114 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
11115 /* port-D for Front */
11116 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11117 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
11118 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011119 /* this has to be set to VREF80 */
11120 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011121 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010011122 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011123 /* port-F for mic-in (front panel) with vref */
11124 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
11125 /* port-G for CLFE (rear panel) */
11126 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11127 /* port-H for side (rear panel) */
11128 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
11129 /* CD-in */
11130 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
11131 /* route front mic to ADC1*/
11132 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11133 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11134 /* Unmute DAC0~3 & spdif out*/
11135 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11136 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11137 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11138 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11139 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11140 /* Unmute Mixer 14 (mic) 1c (Line in)*/
11141 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11142 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11143 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11144 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11145
11146 /* Unmute Stereo Mixer 15 */
11147 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11148 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11149 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011150 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011151
11152 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11153 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11154 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11155 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11156 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11157 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11158 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11159 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011160 /* hp used DAC 3 (Front) */
11161 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011162 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
11163 { }
11164};
11165
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010011166/* additional init verbs for ASUS laptops */
11167static struct hda_verb alc861_asus_laptop_init_verbs[] = {
11168 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
11169 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
11170 { }
11171};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011172
Kailang Yangdf694da2005-12-05 19:42:22 +010011173/*
11174 * generic initialization of ADC, input mixers and output mixers
11175 */
11176static struct hda_verb alc861_auto_init_verbs[] = {
11177 /*
11178 * Unmute ADC0 and set the default input to mic-in
11179 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011180 /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */
Kailang Yangdf694da2005-12-05 19:42:22 +010011181 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11182
11183 /* Unmute DAC0~3 & spdif out*/
11184 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11185 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11186 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11187 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11188 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11189
11190 /* Unmute Mixer 14 (mic) 1c (Line in)*/
11191 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11192 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11193 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11194 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11195
11196 /* Unmute Stereo Mixer 15 */
11197 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11198 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11199 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
11200 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
11201
11202 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11203 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11204 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11205 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11206 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11207 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11208 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11209 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11210
11211 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11212 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011213 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
11214 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011215 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11216 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011217 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
11218 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011219
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011220 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */
Kailang Yangdf694da2005-12-05 19:42:22 +010011221
11222 { }
11223};
11224
Tobin Davisa53d1ae2006-10-17 12:00:28 +020011225static struct hda_verb alc861_toshiba_init_verbs[] = {
11226 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011227
Tobin Davisa53d1ae2006-10-17 12:00:28 +020011228 { }
11229};
11230
11231/* toggle speaker-output according to the hp-jack state */
11232static void alc861_toshiba_automute(struct hda_codec *codec)
11233{
11234 unsigned int present;
11235
11236 present = snd_hda_codec_read(codec, 0x0f, 0,
11237 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020011238 snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
11239 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
11240 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
11241 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020011242}
11243
11244static void alc861_toshiba_unsol_event(struct hda_codec *codec,
11245 unsigned int res)
11246{
Tobin Davisa53d1ae2006-10-17 12:00:28 +020011247 if ((res >> 26) == ALC880_HP_EVENT)
11248 alc861_toshiba_automute(codec);
11249}
11250
Kailang Yangdf694da2005-12-05 19:42:22 +010011251/* pcm configuration: identiacal with ALC880 */
11252#define alc861_pcm_analog_playback alc880_pcm_analog_playback
11253#define alc861_pcm_analog_capture alc880_pcm_analog_capture
11254#define alc861_pcm_digital_playback alc880_pcm_digital_playback
11255#define alc861_pcm_digital_capture alc880_pcm_digital_capture
11256
11257
11258#define ALC861_DIGOUT_NID 0x07
11259
11260static struct hda_channel_mode alc861_8ch_modes[1] = {
11261 { 8, NULL }
11262};
11263
11264static hda_nid_t alc861_dac_nids[4] = {
11265 /* front, surround, clfe, side */
11266 0x03, 0x06, 0x05, 0x04
11267};
11268
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011269static hda_nid_t alc660_dac_nids[3] = {
11270 /* front, clfe, surround */
11271 0x03, 0x05, 0x06
11272};
11273
Kailang Yangdf694da2005-12-05 19:42:22 +010011274static hda_nid_t alc861_adc_nids[1] = {
11275 /* ADC0-2 */
11276 0x08,
11277};
11278
11279static struct hda_input_mux alc861_capture_source = {
11280 .num_items = 5,
11281 .items = {
11282 { "Mic", 0x0 },
11283 { "Front Mic", 0x3 },
11284 { "Line", 0x1 },
11285 { "CD", 0x4 },
11286 { "Mixer", 0x5 },
11287 },
11288};
11289
11290/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011291static int alc861_auto_fill_dac_nids(struct alc_spec *spec,
11292 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010011293{
11294 int i;
11295 hda_nid_t nid;
11296
11297 spec->multiout.dac_nids = spec->private_dac_nids;
11298 for (i = 0; i < cfg->line_outs; i++) {
11299 nid = cfg->line_out_pins[i];
11300 if (nid) {
11301 if (i >= ARRAY_SIZE(alc861_dac_nids))
11302 continue;
11303 spec->multiout.dac_nids[i] = alc861_dac_nids[i];
11304 }
11305 }
11306 spec->multiout.num_dacs = cfg->line_outs;
11307 return 0;
11308}
11309
11310/* add playback controls from the parsed DAC table */
11311static int alc861_auto_create_multi_out_ctls(struct alc_spec *spec,
11312 const struct auto_pin_cfg *cfg)
11313{
11314 char name[32];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011315 static const char *chname[4] = {
11316 "Front", "Surround", NULL /*CLFE*/, "Side"
11317 };
Kailang Yangdf694da2005-12-05 19:42:22 +010011318 hda_nid_t nid;
11319 int i, idx, err;
11320
11321 for (i = 0; i < cfg->line_outs; i++) {
11322 nid = spec->multiout.dac_nids[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011323 if (!nid)
Kailang Yangdf694da2005-12-05 19:42:22 +010011324 continue;
11325 if (nid == 0x05) {
11326 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011327 err = add_control(spec, ALC_CTL_BIND_MUTE,
11328 "Center Playback Switch",
11329 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
11330 HDA_OUTPUT));
11331 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011332 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011333 err = add_control(spec, ALC_CTL_BIND_MUTE,
11334 "LFE Playback Switch",
11335 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
11336 HDA_OUTPUT));
11337 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011338 return err;
11339 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011340 for (idx = 0; idx < ARRAY_SIZE(alc861_dac_nids) - 1;
11341 idx++)
Kailang Yangdf694da2005-12-05 19:42:22 +010011342 if (nid == alc861_dac_nids[idx])
11343 break;
11344 sprintf(name, "%s Playback Switch", chname[idx]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011345 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
11346 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
11347 HDA_OUTPUT));
11348 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011349 return err;
11350 }
11351 }
11352 return 0;
11353}
11354
11355static int alc861_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin)
11356{
11357 int err;
11358 hda_nid_t nid;
11359
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011360 if (!pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010011361 return 0;
11362
11363 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
11364 nid = 0x03;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011365 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
11366 "Headphone Playback Switch",
11367 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
11368 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011369 return err;
11370 spec->multiout.hp_nid = nid;
11371 }
11372 return 0;
11373}
11374
11375/* create playback/capture controls for input pins */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011376static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec,
11377 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010011378{
Kailang Yangdf694da2005-12-05 19:42:22 +010011379 struct hda_input_mux *imux = &spec->private_imux;
11380 int i, err, idx, idx1;
11381
11382 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011383 switch (cfg->input_pins[i]) {
Kailang Yangdf694da2005-12-05 19:42:22 +010011384 case 0x0c:
11385 idx1 = 1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011386 idx = 2; /* Line In */
Kailang Yangdf694da2005-12-05 19:42:22 +010011387 break;
11388 case 0x0f:
11389 idx1 = 2;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011390 idx = 2; /* Line In */
Kailang Yangdf694da2005-12-05 19:42:22 +010011391 break;
11392 case 0x0d:
11393 idx1 = 0;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011394 idx = 1; /* Mic In */
Kailang Yangdf694da2005-12-05 19:42:22 +010011395 break;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011396 case 0x10:
Kailang Yangdf694da2005-12-05 19:42:22 +010011397 idx1 = 3;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011398 idx = 1; /* Mic In */
Kailang Yangdf694da2005-12-05 19:42:22 +010011399 break;
11400 case 0x11:
11401 idx1 = 4;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011402 idx = 0; /* CD */
Kailang Yangdf694da2005-12-05 19:42:22 +010011403 break;
11404 default:
11405 continue;
11406 }
11407
Takashi Iwai4a471b72005-12-07 13:56:29 +010011408 err = new_analog_input(spec, cfg->input_pins[i],
11409 auto_pin_cfg_labels[i], idx, 0x15);
Kailang Yangdf694da2005-12-05 19:42:22 +010011410 if (err < 0)
11411 return err;
11412
Takashi Iwai4a471b72005-12-07 13:56:29 +010011413 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +010011414 imux->items[imux->num_items].index = idx1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011415 imux->num_items++;
Kailang Yangdf694da2005-12-05 19:42:22 +010011416 }
11417 return 0;
11418}
11419
11420static struct snd_kcontrol_new alc861_capture_mixer[] = {
11421 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
11422 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
11423
11424 {
11425 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11426 /* The multiple "Capture Source" controls confuse alsamixer
11427 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +010011428 */
11429 /* .name = "Capture Source", */
11430 .name = "Input Source",
11431 .count = 1,
11432 .info = alc_mux_enum_info,
11433 .get = alc_mux_enum_get,
11434 .put = alc_mux_enum_put,
11435 },
11436 { } /* end */
11437};
11438
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011439static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
11440 hda_nid_t nid,
Kailang Yangdf694da2005-12-05 19:42:22 +010011441 int pin_type, int dac_idx)
11442{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011443 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010011444}
11445
11446static void alc861_auto_init_multi_out(struct hda_codec *codec)
11447{
11448 struct alc_spec *spec = codec->spec;
11449 int i;
11450
Kailang Yangbc9f98a2007-04-12 13:06:07 +020011451 alc_subsystem_id(codec, 0x0e, 0x0f, 0x0b);
Kailang Yangdf694da2005-12-05 19:42:22 +010011452 for (i = 0; i < spec->autocfg.line_outs; i++) {
11453 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020011454 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010011455 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020011456 alc861_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011457 spec->multiout.dac_nids[i]);
Kailang Yangdf694da2005-12-05 19:42:22 +010011458 }
11459}
11460
11461static void alc861_auto_init_hp_out(struct hda_codec *codec)
11462{
11463 struct alc_spec *spec = codec->spec;
11464 hda_nid_t pin;
11465
Takashi Iwaieb06ed82006-09-20 17:10:27 +020011466 pin = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010011467 if (pin) /* connect to front */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011468 alc861_auto_set_output_and_unmute(codec, pin, PIN_HP,
11469 spec->multiout.dac_nids[0]);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011470 pin = spec->autocfg.speaker_pins[0];
11471 if (pin)
11472 alc861_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +010011473}
11474
11475static void alc861_auto_init_analog_input(struct hda_codec *codec)
11476{
11477 struct alc_spec *spec = codec->spec;
11478 int i;
11479
11480 for (i = 0; i < AUTO_PIN_LAST; i++) {
11481 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011482 if (nid >= 0x0c && nid <= 0x11) {
11483 snd_hda_codec_write(codec, nid, 0,
11484 AC_VERB_SET_PIN_WIDGET_CONTROL,
11485 i <= AUTO_PIN_FRONT_MIC ?
11486 PIN_VREF80 : PIN_IN);
Kailang Yangdf694da2005-12-05 19:42:22 +010011487 }
11488 }
11489}
11490
11491/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011492/* return 1 if successful, 0 if the proper config is not found,
11493 * or a negative error code
11494 */
Kailang Yangdf694da2005-12-05 19:42:22 +010011495static int alc861_parse_auto_config(struct hda_codec *codec)
11496{
11497 struct alc_spec *spec = codec->spec;
11498 int err;
11499 static hda_nid_t alc861_ignore[] = { 0x1d, 0 };
11500
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011501 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
11502 alc861_ignore);
11503 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011504 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011505 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010011506 return 0; /* can't find valid BIOS pin config */
11507
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011508 err = alc861_auto_fill_dac_nids(spec, &spec->autocfg);
11509 if (err < 0)
11510 return err;
11511 err = alc861_auto_create_multi_out_ctls(spec, &spec->autocfg);
11512 if (err < 0)
11513 return err;
11514 err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
11515 if (err < 0)
11516 return err;
11517 err = alc861_auto_create_analog_input_ctls(spec, &spec->autocfg);
11518 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011519 return err;
11520
11521 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
11522
11523 if (spec->autocfg.dig_out_pin)
11524 spec->multiout.dig_out_nid = ALC861_DIGOUT_NID;
11525
11526 if (spec->kctl_alloc)
11527 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
11528
11529 spec->init_verbs[spec->num_init_verbs++] = alc861_auto_init_verbs;
11530
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020011531 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +010011532 spec->input_mux = &spec->private_imux;
11533
11534 spec->adc_nids = alc861_adc_nids;
11535 spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
11536 spec->mixers[spec->num_mixers] = alc861_capture_mixer;
11537 spec->num_mixers++;
11538
11539 return 1;
11540}
11541
Takashi Iwaiae6b8132006-03-03 16:47:17 +010011542/* additional initialization for auto-configuration model */
11543static void alc861_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010011544{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011545 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010011546 alc861_auto_init_multi_out(codec);
11547 alc861_auto_init_hp_out(codec);
11548 alc861_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011549 if (spec->unsol_event)
11550 alc_sku_automute(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010011551}
11552
Takashi Iwaicb53c622007-08-10 17:21:45 +020011553#ifdef CONFIG_SND_HDA_POWER_SAVE
11554static struct hda_amp_list alc861_loopbacks[] = {
11555 { 0x15, HDA_INPUT, 0 },
11556 { 0x15, HDA_INPUT, 1 },
11557 { 0x15, HDA_INPUT, 2 },
11558 { 0x15, HDA_INPUT, 3 },
11559 { } /* end */
11560};
11561#endif
11562
Kailang Yangdf694da2005-12-05 19:42:22 +010011563
11564/*
11565 * configuration and preset
11566 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011567static const char *alc861_models[ALC861_MODEL_LAST] = {
11568 [ALC861_3ST] = "3stack",
11569 [ALC660_3ST] = "3stack-660",
11570 [ALC861_3ST_DIG] = "3stack-dig",
11571 [ALC861_6ST_DIG] = "6stack-dig",
11572 [ALC861_UNIWILL_M31] = "uniwill-m31",
11573 [ALC861_TOSHIBA] = "toshiba",
11574 [ALC861_ASUS] = "asus",
11575 [ALC861_ASUS_LAPTOP] = "asus-laptop",
11576 [ALC861_AUTO] = "auto",
11577};
11578
11579static struct snd_pci_quirk alc861_cfg_tbl[] = {
Takashi Iwai687a47b2007-01-10 11:25:58 +010011580 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011581 SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
11582 SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
11583 SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011584 SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
Kailang Yang83c34212007-07-05 11:43:05 +020011585 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
Tobin Davisad5e7732007-01-08 10:57:32 +010011586 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
Takashi Iwai341d4eb2007-07-09 17:53:18 +020011587 /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
11588 * Any other models that need this preset?
11589 */
11590 /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
Claudio Matsuokaef64adb2007-07-14 00:26:16 +020011591 SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
11592 SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011593 SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
11594 SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
11595 SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
11596 /* FIXME: the below seems conflict */
11597 /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
11598 SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
11599 SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
Kailang Yangdf694da2005-12-05 19:42:22 +010011600 {}
11601};
11602
11603static struct alc_config_preset alc861_presets[] = {
11604 [ALC861_3ST] = {
11605 .mixers = { alc861_3ST_mixer },
11606 .init_verbs = { alc861_threestack_init_verbs },
11607 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
11608 .dac_nids = alc861_dac_nids,
11609 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
11610 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020011611 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010011612 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11613 .adc_nids = alc861_adc_nids,
11614 .input_mux = &alc861_capture_source,
11615 },
11616 [ALC861_3ST_DIG] = {
11617 .mixers = { alc861_base_mixer },
11618 .init_verbs = { alc861_threestack_init_verbs },
11619 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
11620 .dac_nids = alc861_dac_nids,
11621 .dig_out_nid = ALC861_DIGOUT_NID,
11622 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
11623 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020011624 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010011625 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11626 .adc_nids = alc861_adc_nids,
11627 .input_mux = &alc861_capture_source,
11628 },
11629 [ALC861_6ST_DIG] = {
11630 .mixers = { alc861_base_mixer },
11631 .init_verbs = { alc861_base_init_verbs },
11632 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
11633 .dac_nids = alc861_dac_nids,
11634 .dig_out_nid = ALC861_DIGOUT_NID,
11635 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
11636 .channel_mode = alc861_8ch_modes,
11637 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11638 .adc_nids = alc861_adc_nids,
11639 .input_mux = &alc861_capture_source,
11640 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011641 [ALC660_3ST] = {
11642 .mixers = { alc861_3ST_mixer },
11643 .init_verbs = { alc861_threestack_init_verbs },
11644 .num_dacs = ARRAY_SIZE(alc660_dac_nids),
11645 .dac_nids = alc660_dac_nids,
11646 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
11647 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020011648 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011649 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11650 .adc_nids = alc861_adc_nids,
11651 .input_mux = &alc861_capture_source,
11652 },
Takashi Iwai22309c32006-08-09 16:57:28 +020011653 [ALC861_UNIWILL_M31] = {
11654 .mixers = { alc861_uniwill_m31_mixer },
11655 .init_verbs = { alc861_uniwill_m31_init_verbs },
11656 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
11657 .dac_nids = alc861_dac_nids,
11658 .dig_out_nid = ALC861_DIGOUT_NID,
11659 .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
11660 .channel_mode = alc861_uniwill_m31_modes,
11661 .need_dac_fix = 1,
11662 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11663 .adc_nids = alc861_adc_nids,
11664 .input_mux = &alc861_capture_source,
11665 },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020011666 [ALC861_TOSHIBA] = {
11667 .mixers = { alc861_toshiba_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011668 .init_verbs = { alc861_base_init_verbs,
11669 alc861_toshiba_init_verbs },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020011670 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
11671 .dac_nids = alc861_dac_nids,
11672 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
11673 .channel_mode = alc883_3ST_2ch_modes,
11674 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11675 .adc_nids = alc861_adc_nids,
11676 .input_mux = &alc861_capture_source,
11677 .unsol_event = alc861_toshiba_unsol_event,
11678 .init_hook = alc861_toshiba_automute,
11679 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020011680 [ALC861_ASUS] = {
11681 .mixers = { alc861_asus_mixer },
11682 .init_verbs = { alc861_asus_init_verbs },
11683 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
11684 .dac_nids = alc861_dac_nids,
11685 .dig_out_nid = ALC861_DIGOUT_NID,
11686 .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
11687 .channel_mode = alc861_asus_modes,
11688 .need_dac_fix = 1,
11689 .hp_nid = 0x06,
11690 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11691 .adc_nids = alc861_adc_nids,
11692 .input_mux = &alc861_capture_source,
11693 },
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010011694 [ALC861_ASUS_LAPTOP] = {
11695 .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
11696 .init_verbs = { alc861_asus_init_verbs,
11697 alc861_asus_laptop_init_verbs },
11698 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
11699 .dac_nids = alc861_dac_nids,
11700 .dig_out_nid = ALC861_DIGOUT_NID,
11701 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
11702 .channel_mode = alc883_3ST_2ch_modes,
11703 .need_dac_fix = 1,
11704 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
11705 .adc_nids = alc861_adc_nids,
11706 .input_mux = &alc861_capture_source,
11707 },
11708};
Kailang Yangdf694da2005-12-05 19:42:22 +010011709
11710
11711static int patch_alc861(struct hda_codec *codec)
11712{
11713 struct alc_spec *spec;
11714 int board_config;
11715 int err;
11716
Robert P. J. Daydc041e02006-12-19 14:44:15 +010011717 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010011718 if (spec == NULL)
11719 return -ENOMEM;
11720
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011721 codec->spec = spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010011722
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011723 board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
11724 alc861_models,
11725 alc861_cfg_tbl);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011726
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011727 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011728 printk(KERN_INFO "hda_codec: Unknown model for ALC861, "
11729 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010011730 board_config = ALC861_AUTO;
11731 }
11732
11733 if (board_config == ALC861_AUTO) {
11734 /* automatic parse from the BIOS config */
11735 err = alc861_parse_auto_config(codec);
11736 if (err < 0) {
11737 alc_free(codec);
11738 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011739 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011740 printk(KERN_INFO
11741 "hda_codec: Cannot set up configuration "
11742 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010011743 board_config = ALC861_3ST_DIG;
11744 }
11745 }
11746
11747 if (board_config != ALC861_AUTO)
11748 setup_preset(spec, &alc861_presets[board_config]);
11749
11750 spec->stream_name_analog = "ALC861 Analog";
11751 spec->stream_analog_playback = &alc861_pcm_analog_playback;
11752 spec->stream_analog_capture = &alc861_pcm_analog_capture;
11753
11754 spec->stream_name_digital = "ALC861 Digital";
11755 spec->stream_digital_playback = &alc861_pcm_digital_playback;
11756 spec->stream_digital_capture = &alc861_pcm_digital_capture;
11757
Takashi Iwai2134ea42008-01-10 16:53:55 +010011758 spec->vmaster_nid = 0x03;
11759
Kailang Yangdf694da2005-12-05 19:42:22 +010011760 codec->patch_ops = alc_patch_ops;
11761 if (board_config == ALC861_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010011762 spec->init_hook = alc861_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020011763#ifdef CONFIG_SND_HDA_POWER_SAVE
11764 if (!spec->loopback.amplist)
11765 spec->loopback.amplist = alc861_loopbacks;
11766#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010011767
11768 return 0;
11769}
11770
11771/*
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011772 * ALC861-VD support
11773 *
11774 * Based on ALC882
11775 *
11776 * In addition, an independent DAC
11777 */
11778#define ALC861VD_DIGOUT_NID 0x06
11779
11780static hda_nid_t alc861vd_dac_nids[4] = {
11781 /* front, surr, clfe, side surr */
11782 0x02, 0x03, 0x04, 0x05
11783};
11784
11785/* dac_nids for ALC660vd are in a different order - according to
11786 * Realtek's driver.
11787 * This should probably tesult in a different mixer for 6stack models
11788 * of ALC660vd codecs, but for now there is only 3stack mixer
11789 * - and it is the same as in 861vd.
11790 * adc_nids in ALC660vd are (is) the same as in 861vd
11791 */
11792static hda_nid_t alc660vd_dac_nids[3] = {
11793 /* front, rear, clfe, rear_surr */
11794 0x02, 0x04, 0x03
11795};
11796
11797static hda_nid_t alc861vd_adc_nids[1] = {
11798 /* ADC0 */
11799 0x09,
11800};
11801
Takashi Iwaie1406342008-02-11 18:32:32 +010011802static hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
11803
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011804/* input MUX */
11805/* FIXME: should be a matrix-type input source selection */
11806static struct hda_input_mux alc861vd_capture_source = {
11807 .num_items = 4,
11808 .items = {
11809 { "Mic", 0x0 },
11810 { "Front Mic", 0x1 },
11811 { "Line", 0x2 },
11812 { "CD", 0x4 },
11813 },
11814};
11815
Kailang Yang272a5272007-05-14 11:00:38 +020011816static struct hda_input_mux alc861vd_dallas_capture_source = {
11817 .num_items = 3,
11818 .items = {
11819 { "Front Mic", 0x0 },
11820 { "ATAPI Mic", 0x1 },
11821 { "Line In", 0x5 },
11822 },
11823};
11824
Kailang Yangd1a991a2007-08-15 16:21:59 +020011825static struct hda_input_mux alc861vd_hp_capture_source = {
11826 .num_items = 2,
11827 .items = {
11828 { "Front Mic", 0x0 },
11829 { "ATAPI Mic", 0x1 },
11830 },
11831};
11832
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011833#define alc861vd_mux_enum_info alc_mux_enum_info
11834#define alc861vd_mux_enum_get alc_mux_enum_get
Takashi Iwaie1406342008-02-11 18:32:32 +010011835/* ALC861VD has the ALC882-type input selection (but has only one ADC) */
11836#define alc861vd_mux_enum_put alc882_mux_enum_put
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011837
11838/*
11839 * 2ch mode
11840 */
11841static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
11842 { 2, NULL }
11843};
11844
11845/*
11846 * 6ch mode
11847 */
11848static struct hda_verb alc861vd_6stack_ch6_init[] = {
11849 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
11850 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11851 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11852 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11853 { } /* end */
11854};
11855
11856/*
11857 * 8ch mode
11858 */
11859static struct hda_verb alc861vd_6stack_ch8_init[] = {
11860 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11861 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11862 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11863 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11864 { } /* end */
11865};
11866
11867static struct hda_channel_mode alc861vd_6stack_modes[2] = {
11868 { 6, alc861vd_6stack_ch6_init },
11869 { 8, alc861vd_6stack_ch8_init },
11870};
11871
11872static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
11873 {
11874 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11875 .name = "Channel Mode",
11876 .info = alc_ch_mode_info,
11877 .get = alc_ch_mode_get,
11878 .put = alc_ch_mode_put,
11879 },
11880 { } /* end */
11881};
11882
11883static struct snd_kcontrol_new alc861vd_capture_mixer[] = {
11884 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
11885 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
11886
11887 {
11888 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11889 /* The multiple "Capture Source" controls confuse alsamixer
11890 * So call somewhat different..
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010011891 */
11892 /* .name = "Capture Source", */
11893 .name = "Input Source",
11894 .count = 1,
11895 .info = alc861vd_mux_enum_info,
11896 .get = alc861vd_mux_enum_get,
11897 .put = alc861vd_mux_enum_put,
11898 },
11899 { } /* end */
11900};
11901
11902/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
11903 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
11904 */
11905static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
11906 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11907 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
11908
11909 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
11910 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
11911
11912 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
11913 HDA_OUTPUT),
11914 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
11915 HDA_OUTPUT),
11916 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
11917 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
11918
11919 HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
11920 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
11921
11922 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
11923
11924 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11925 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11926 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11927
11928 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11929 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11930 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
11931
11932 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11933 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11934
11935 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11936 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11937
11938 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
11939 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
11940
11941 { } /* end */
11942};
11943
11944static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
11945 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11946 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
11947
11948 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
11949
11950 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11951 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11952 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11953
11954 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11955 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11956 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
11957
11958 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11959 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11960
11961 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11962 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11963
11964 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
11965 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
11966
11967 { } /* end */
11968};
11969
Kailang Yangbdd148a2007-05-08 15:19:08 +020011970static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
11971 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11972 /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
11973 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11974
11975 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
11976
11977 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11978 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11979 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11980
11981 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11982 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11983 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
11984
11985 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11986 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11987
11988 { } /* end */
11989};
11990
Kailang Yang272a5272007-05-14 11:00:38 +020011991/* Pin assignment: Front=0x14, HP = 0x15,
11992 * Front Mic=0x18, ATAPI Mic = 0x19, Line In = 0x1d
11993 */
11994static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
11995 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11996 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
11997 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
11998 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
11999 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12000 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12001 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12002 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
12003 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x05, HDA_INPUT),
12004 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020012005 { } /* end */
12006};
12007
Kailang Yangd1a991a2007-08-15 16:21:59 +020012008/* Pin assignment: Speaker=0x14, Line-out = 0x15,
12009 * Front Mic=0x18, ATAPI Mic = 0x19,
12010 */
12011static struct snd_kcontrol_new alc861vd_hp_mixer[] = {
12012 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12013 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
12014 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
12015 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
12016 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12017 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12018 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12019 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
12020
12021 { } /* end */
12022};
12023
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012024/*
12025 * generic initialization of ADC, input mixers and output mixers
12026 */
12027static struct hda_verb alc861vd_volume_init_verbs[] = {
12028 /*
12029 * Unmute ADC0 and set the default input to mic-in
12030 */
12031 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12032 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12033
12034 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
12035 * the analog-loopback mixer widget
12036 */
12037 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020012038 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12039 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12040 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12041 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12042 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012043
12044 /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yangbdd148a2007-05-08 15:19:08 +020012045 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12046 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12047 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012048 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012049
12050 /*
12051 * Set up output mixers (0x02 - 0x05)
12052 */
12053 /* set vol=0 to output mixers */
12054 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12055 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12056 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12057 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12058
12059 /* set up input amps for analog loopback */
12060 /* Amp Indices: DAC = 0, mixer = 1 */
12061 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12062 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12063 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12064 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12065 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12066 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12067 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12068 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12069
12070 { }
12071};
12072
12073/*
12074 * 3-stack pin configuration:
12075 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
12076 */
12077static struct hda_verb alc861vd_3stack_init_verbs[] = {
12078 /*
12079 * Set pin mode and muting
12080 */
12081 /* set front pin widgets 0x14 for output */
12082 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12083 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12084 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
12085
12086 /* Mic (rear) pin: input vref at 80% */
12087 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12088 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12089 /* Front Mic pin: input vref at 80% */
12090 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12091 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12092 /* Line In pin: input */
12093 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12094 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12095 /* Line-2 In: Headphone output (output 0 - 0x0c) */
12096 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12097 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12098 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
12099 /* CD pin widget for input */
12100 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12101
12102 { }
12103};
12104
12105/*
12106 * 6-stack pin configuration:
12107 */
12108static struct hda_verb alc861vd_6stack_init_verbs[] = {
12109 /*
12110 * Set pin mode and muting
12111 */
12112 /* set front pin widgets 0x14 for output */
12113 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12114 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12115 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
12116
12117 /* Rear Pin: output 1 (0x0d) */
12118 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12119 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12120 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12121 /* CLFE Pin: output 2 (0x0e) */
12122 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12123 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12124 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
12125 /* Side Pin: output 3 (0x0f) */
12126 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12127 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12128 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
12129
12130 /* Mic (rear) pin: input vref at 80% */
12131 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12132 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12133 /* Front Mic pin: input vref at 80% */
12134 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12135 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12136 /* Line In pin: input */
12137 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12138 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12139 /* Line-2 In: Headphone output (output 0 - 0x0c) */
12140 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12141 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12142 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
12143 /* CD pin widget for input */
12144 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12145
12146 { }
12147};
12148
Kailang Yangbdd148a2007-05-08 15:19:08 +020012149static struct hda_verb alc861vd_eapd_verbs[] = {
12150 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
12151 { }
12152};
12153
12154static struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
12155 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12156 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12157 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
12158 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12159 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
12160 {}
12161};
12162
12163/* toggle speaker-output according to the hp-jack state */
12164static void alc861vd_lenovo_hp_automute(struct hda_codec *codec)
12165{
12166 unsigned int present;
12167 unsigned char bits;
12168
12169 present = snd_hda_codec_read(codec, 0x1b, 0,
12170 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020012171 bits = present ? HDA_AMP_MUTE : 0;
12172 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
12173 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020012174}
12175
12176static void alc861vd_lenovo_mic_automute(struct hda_codec *codec)
12177{
12178 unsigned int present;
12179 unsigned char bits;
12180
12181 present = snd_hda_codec_read(codec, 0x18, 0,
12182 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020012183 bits = present ? HDA_AMP_MUTE : 0;
12184 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
12185 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020012186}
12187
12188static void alc861vd_lenovo_automute(struct hda_codec *codec)
12189{
12190 alc861vd_lenovo_hp_automute(codec);
12191 alc861vd_lenovo_mic_automute(codec);
12192}
12193
12194static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
12195 unsigned int res)
12196{
12197 switch (res >> 26) {
12198 case ALC880_HP_EVENT:
12199 alc861vd_lenovo_hp_automute(codec);
12200 break;
12201 case ALC880_MIC_EVENT:
12202 alc861vd_lenovo_mic_automute(codec);
12203 break;
12204 }
12205}
12206
Kailang Yang272a5272007-05-14 11:00:38 +020012207static struct hda_verb alc861vd_dallas_verbs[] = {
12208 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12209 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12210 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12211 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12212
12213 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12214 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12215 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12216 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12217 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12218 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12219 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12220 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12221
12222 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12223 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12224 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12225 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12226 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12227 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12228 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12229 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12230
12231 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
12232 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12233 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
12234 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12235 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12236 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12237 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12238 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12239
12240 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12241 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12242 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12243 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12244
12245 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12246 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12247 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12248
12249 { } /* end */
12250};
12251
12252/* toggle speaker-output according to the hp-jack state */
12253static void alc861vd_dallas_automute(struct hda_codec *codec)
12254{
12255 unsigned int present;
12256
12257 present = snd_hda_codec_read(codec, 0x15, 0,
12258 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020012259 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
12260 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +020012261}
12262
12263static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int res)
12264{
12265 if ((res >> 26) == ALC880_HP_EVENT)
12266 alc861vd_dallas_automute(codec);
12267}
12268
Takashi Iwaicb53c622007-08-10 17:21:45 +020012269#ifdef CONFIG_SND_HDA_POWER_SAVE
12270#define alc861vd_loopbacks alc880_loopbacks
12271#endif
12272
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012273/* pcm configuration: identiacal with ALC880 */
12274#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback
12275#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture
12276#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback
12277#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture
12278
12279/*
12280 * configuration and preset
12281 */
12282static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
12283 [ALC660VD_3ST] = "3stack-660",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020012284 [ALC660VD_3ST_DIG] = "3stack-660-digout",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012285 [ALC861VD_3ST] = "3stack",
12286 [ALC861VD_3ST_DIG] = "3stack-digout",
12287 [ALC861VD_6ST_DIG] = "6stack-digout",
Kailang Yangbdd148a2007-05-08 15:19:08 +020012288 [ALC861VD_LENOVO] = "lenovo",
Kailang Yang272a5272007-05-14 11:00:38 +020012289 [ALC861VD_DALLAS] = "dallas",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020012290 [ALC861VD_HP] = "hp",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012291 [ALC861VD_AUTO] = "auto",
12292};
12293
12294static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012295 SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
12296 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
Takashi Iwai07e038b2007-02-15 18:23:41 +010012297 SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012298 SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),
Mike Crash6963f842007-06-25 12:12:51 +020012299 SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012300 SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012301 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai38baf5a2007-08-16 17:52:43 +020012302 /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
Kailang Yang272a5272007-05-14 11:00:38 +020012303 SND_PCI_QUIRK(0x1179, 0xff01, "DALLAS", ALC861VD_DALLAS),
Takashi Iwai542d7c62007-08-16 18:57:30 +020012304 SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
Takashi Iwai39c5d412007-08-15 16:24:17 +020012305 SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012306 SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO),
12307 SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO),
Tobin Davis625dc0b2007-07-30 21:42:10 +020012308 SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012309 {}
12310};
12311
12312static struct alc_config_preset alc861vd_presets[] = {
12313 [ALC660VD_3ST] = {
12314 .mixers = { alc861vd_3st_mixer },
12315 .init_verbs = { alc861vd_volume_init_verbs,
12316 alc861vd_3stack_init_verbs },
12317 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
12318 .dac_nids = alc660vd_dac_nids,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012319 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12320 .channel_mode = alc861vd_3stack_2ch_modes,
12321 .input_mux = &alc861vd_capture_source,
12322 },
Mike Crash6963f842007-06-25 12:12:51 +020012323 [ALC660VD_3ST_DIG] = {
12324 .mixers = { alc861vd_3st_mixer },
12325 .init_verbs = { alc861vd_volume_init_verbs,
12326 alc861vd_3stack_init_verbs },
12327 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
12328 .dac_nids = alc660vd_dac_nids,
12329 .dig_out_nid = ALC861VD_DIGOUT_NID,
Mike Crash6963f842007-06-25 12:12:51 +020012330 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12331 .channel_mode = alc861vd_3stack_2ch_modes,
12332 .input_mux = &alc861vd_capture_source,
12333 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012334 [ALC861VD_3ST] = {
12335 .mixers = { alc861vd_3st_mixer },
12336 .init_verbs = { alc861vd_volume_init_verbs,
12337 alc861vd_3stack_init_verbs },
12338 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
12339 .dac_nids = alc861vd_dac_nids,
12340 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12341 .channel_mode = alc861vd_3stack_2ch_modes,
12342 .input_mux = &alc861vd_capture_source,
12343 },
12344 [ALC861VD_3ST_DIG] = {
12345 .mixers = { alc861vd_3st_mixer },
12346 .init_verbs = { alc861vd_volume_init_verbs,
12347 alc861vd_3stack_init_verbs },
12348 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
12349 .dac_nids = alc861vd_dac_nids,
12350 .dig_out_nid = ALC861VD_DIGOUT_NID,
12351 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12352 .channel_mode = alc861vd_3stack_2ch_modes,
12353 .input_mux = &alc861vd_capture_source,
12354 },
12355 [ALC861VD_6ST_DIG] = {
12356 .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
12357 .init_verbs = { alc861vd_volume_init_verbs,
12358 alc861vd_6stack_init_verbs },
12359 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
12360 .dac_nids = alc861vd_dac_nids,
12361 .dig_out_nid = ALC861VD_DIGOUT_NID,
12362 .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
12363 .channel_mode = alc861vd_6stack_modes,
12364 .input_mux = &alc861vd_capture_source,
12365 },
Kailang Yangbdd148a2007-05-08 15:19:08 +020012366 [ALC861VD_LENOVO] = {
12367 .mixers = { alc861vd_lenovo_mixer },
12368 .init_verbs = { alc861vd_volume_init_verbs,
12369 alc861vd_3stack_init_verbs,
12370 alc861vd_eapd_verbs,
12371 alc861vd_lenovo_unsol_verbs },
12372 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
12373 .dac_nids = alc660vd_dac_nids,
Kailang Yangbdd148a2007-05-08 15:19:08 +020012374 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12375 .channel_mode = alc861vd_3stack_2ch_modes,
12376 .input_mux = &alc861vd_capture_source,
12377 .unsol_event = alc861vd_lenovo_unsol_event,
12378 .init_hook = alc861vd_lenovo_automute,
12379 },
Kailang Yang272a5272007-05-14 11:00:38 +020012380 [ALC861VD_DALLAS] = {
12381 .mixers = { alc861vd_dallas_mixer },
12382 .init_verbs = { alc861vd_dallas_verbs },
12383 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
12384 .dac_nids = alc861vd_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020012385 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12386 .channel_mode = alc861vd_3stack_2ch_modes,
12387 .input_mux = &alc861vd_dallas_capture_source,
12388 .unsol_event = alc861vd_dallas_unsol_event,
12389 .init_hook = alc861vd_dallas_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +020012390 },
12391 [ALC861VD_HP] = {
12392 .mixers = { alc861vd_hp_mixer },
12393 .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
12394 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
12395 .dac_nids = alc861vd_dac_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020012396 .dig_out_nid = ALC861VD_DIGOUT_NID,
Kailang Yangd1a991a2007-08-15 16:21:59 +020012397 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
12398 .channel_mode = alc861vd_3stack_2ch_modes,
12399 .input_mux = &alc861vd_hp_capture_source,
12400 .unsol_event = alc861vd_dallas_unsol_event,
12401 .init_hook = alc861vd_dallas_automute,
12402 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012403};
12404
12405/*
12406 * BIOS auto configuration
12407 */
12408static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
12409 hda_nid_t nid, int pin_type, int dac_idx)
12410{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012411 alc_set_pin_output(codec, nid, pin_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012412}
12413
12414static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
12415{
12416 struct alc_spec *spec = codec->spec;
12417 int i;
12418
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012419 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012420 for (i = 0; i <= HDA_SIDE; i++) {
12421 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020012422 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012423 if (nid)
12424 alc861vd_auto_set_output_and_unmute(codec, nid,
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020012425 pin_type, i);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012426 }
12427}
12428
12429
12430static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
12431{
12432 struct alc_spec *spec = codec->spec;
12433 hda_nid_t pin;
12434
12435 pin = spec->autocfg.hp_pins[0];
12436 if (pin) /* connect to front and use dac 0 */
12437 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012438 pin = spec->autocfg.speaker_pins[0];
12439 if (pin)
12440 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012441}
12442
12443#define alc861vd_is_input_pin(nid) alc880_is_input_pin(nid)
12444#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID
12445
12446static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
12447{
12448 struct alc_spec *spec = codec->spec;
12449 int i;
12450
12451 for (i = 0; i < AUTO_PIN_LAST; i++) {
12452 hda_nid_t nid = spec->autocfg.input_pins[i];
12453 if (alc861vd_is_input_pin(nid)) {
12454 snd_hda_codec_write(codec, nid, 0,
12455 AC_VERB_SET_PIN_WIDGET_CONTROL,
12456 i <= AUTO_PIN_FRONT_MIC ?
12457 PIN_VREF80 : PIN_IN);
12458 if (nid != ALC861VD_PIN_CD_NID)
12459 snd_hda_codec_write(codec, nid, 0,
12460 AC_VERB_SET_AMP_GAIN_MUTE,
12461 AMP_OUT_MUTE);
12462 }
12463 }
12464}
12465
12466#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
12467#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
12468
12469/* add playback controls from the parsed DAC table */
12470/* Based on ALC880 version. But ALC861VD has separate,
12471 * different NIDs for mute/unmute switch and volume control */
12472static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
12473 const struct auto_pin_cfg *cfg)
12474{
12475 char name[32];
12476 static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
12477 hda_nid_t nid_v, nid_s;
12478 int i, err;
12479
12480 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012481 if (!spec->multiout.dac_nids[i])
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012482 continue;
12483 nid_v = alc861vd_idx_to_mixer_vol(
12484 alc880_dac_to_idx(
12485 spec->multiout.dac_nids[i]));
12486 nid_s = alc861vd_idx_to_mixer_switch(
12487 alc880_dac_to_idx(
12488 spec->multiout.dac_nids[i]));
12489
12490 if (i == 2) {
12491 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012492 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12493 "Center Playback Volume",
12494 HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
12495 HDA_OUTPUT));
12496 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012497 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012498 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12499 "LFE Playback Volume",
12500 HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
12501 HDA_OUTPUT));
12502 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012503 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012504 err = add_control(spec, ALC_CTL_BIND_MUTE,
12505 "Center Playback Switch",
12506 HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
12507 HDA_INPUT));
12508 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012509 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012510 err = add_control(spec, ALC_CTL_BIND_MUTE,
12511 "LFE Playback Switch",
12512 HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
12513 HDA_INPUT));
12514 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012515 return err;
12516 } else {
12517 sprintf(name, "%s Playback Volume", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012518 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
12519 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
12520 HDA_OUTPUT));
12521 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012522 return err;
12523 sprintf(name, "%s Playback Switch", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012524 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
Kailang Yangbdd148a2007-05-08 15:19:08 +020012525 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012526 HDA_INPUT));
12527 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012528 return err;
12529 }
12530 }
12531 return 0;
12532}
12533
12534/* add playback controls for speaker and HP outputs */
12535/* Based on ALC880 version. But ALC861VD has separate,
12536 * different NIDs for mute/unmute switch and volume control */
12537static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
12538 hda_nid_t pin, const char *pfx)
12539{
12540 hda_nid_t nid_v, nid_s;
12541 int err;
12542 char name[32];
12543
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012544 if (!pin)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012545 return 0;
12546
12547 if (alc880_is_fixed_pin(pin)) {
12548 nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
12549 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012550 if (!spec->multiout.hp_nid)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012551 spec->multiout.hp_nid = nid_v;
12552 else
12553 spec->multiout.extra_out_nid[0] = nid_v;
12554 /* control HP volume/switch on the output mixer amp */
12555 nid_v = alc861vd_idx_to_mixer_vol(
12556 alc880_fixed_pin_idx(pin));
12557 nid_s = alc861vd_idx_to_mixer_switch(
12558 alc880_fixed_pin_idx(pin));
12559
12560 sprintf(name, "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012561 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
12562 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
12563 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012564 return err;
12565 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012566 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
12567 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
12568 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012569 return err;
12570 } else if (alc880_is_multi_pin(pin)) {
12571 /* set manual connection */
12572 /* we have only a switch on HP-out PIN */
12573 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012574 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
12575 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
12576 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012577 return err;
12578 }
12579 return 0;
12580}
12581
12582/* parse the BIOS configuration and set up the alc_spec
12583 * return 1 if successful, 0 if the proper config is not found,
12584 * or a negative error code
12585 * Based on ALC880 version - had to change it to override
12586 * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
12587static int alc861vd_parse_auto_config(struct hda_codec *codec)
12588{
12589 struct alc_spec *spec = codec->spec;
12590 int err;
12591 static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
12592
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012593 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
12594 alc861vd_ignore);
12595 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012596 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012597 if (!spec->autocfg.line_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012598 return 0; /* can't find valid BIOS pin config */
12599
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012600 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
12601 if (err < 0)
12602 return err;
12603 err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
12604 if (err < 0)
12605 return err;
12606 err = alc861vd_auto_create_extra_out(spec,
12607 spec->autocfg.speaker_pins[0],
12608 "Speaker");
12609 if (err < 0)
12610 return err;
12611 err = alc861vd_auto_create_extra_out(spec,
12612 spec->autocfg.hp_pins[0],
12613 "Headphone");
12614 if (err < 0)
12615 return err;
12616 err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg);
12617 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012618 return err;
12619
12620 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
12621
12622 if (spec->autocfg.dig_out_pin)
12623 spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID;
12624
12625 if (spec->kctl_alloc)
12626 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
12627
12628 spec->init_verbs[spec->num_init_verbs++]
12629 = alc861vd_volume_init_verbs;
12630
12631 spec->num_mux_defs = 1;
12632 spec->input_mux = &spec->private_imux;
12633
Takashi Iwai776e1842007-08-29 15:07:11 +020012634 err = alc_auto_add_mic_boost(codec);
12635 if (err < 0)
12636 return err;
12637
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012638 return 1;
12639}
12640
12641/* additional initialization for auto-configuration model */
12642static void alc861vd_auto_init(struct hda_codec *codec)
12643{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012644 struct alc_spec *spec = codec->spec;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012645 alc861vd_auto_init_multi_out(codec);
12646 alc861vd_auto_init_hp_out(codec);
12647 alc861vd_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012648 if (spec->unsol_event)
12649 alc_sku_automute(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012650}
12651
12652static int patch_alc861vd(struct hda_codec *codec)
12653{
12654 struct alc_spec *spec;
12655 int err, board_config;
12656
12657 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
12658 if (spec == NULL)
12659 return -ENOMEM;
12660
12661 codec->spec = spec;
12662
12663 board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
12664 alc861vd_models,
12665 alc861vd_cfg_tbl);
12666
12667 if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
12668 printk(KERN_INFO "hda_codec: Unknown model for ALC660VD/"
12669 "ALC861VD, trying auto-probe from BIOS...\n");
12670 board_config = ALC861VD_AUTO;
12671 }
12672
12673 if (board_config == ALC861VD_AUTO) {
12674 /* automatic parse from the BIOS config */
12675 err = alc861vd_parse_auto_config(codec);
12676 if (err < 0) {
12677 alc_free(codec);
12678 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012679 } else if (!err) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012680 printk(KERN_INFO
12681 "hda_codec: Cannot set up configuration "
12682 "from BIOS. Using base mode...\n");
12683 board_config = ALC861VD_3ST;
12684 }
12685 }
12686
12687 if (board_config != ALC861VD_AUTO)
12688 setup_preset(spec, &alc861vd_presets[board_config]);
12689
12690 spec->stream_name_analog = "ALC861VD Analog";
12691 spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
12692 spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
12693
12694 spec->stream_name_digital = "ALC861VD Digital";
12695 spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
12696 spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
12697
12698 spec->adc_nids = alc861vd_adc_nids;
12699 spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
Takashi Iwaie1406342008-02-11 18:32:32 +010012700 spec->capsrc_nids = alc861vd_capsrc_nids;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012701
12702 spec->mixers[spec->num_mixers] = alc861vd_capture_mixer;
12703 spec->num_mixers++;
12704
Takashi Iwai2134ea42008-01-10 16:53:55 +010012705 spec->vmaster_nid = 0x02;
12706
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012707 codec->patch_ops = alc_patch_ops;
12708
12709 if (board_config == ALC861VD_AUTO)
12710 spec->init_hook = alc861vd_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020012711#ifdef CONFIG_SND_HDA_POWER_SAVE
12712 if (!spec->loopback.amplist)
12713 spec->loopback.amplist = alc861vd_loopbacks;
12714#endif
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010012715
12716 return 0;
12717}
12718
12719/*
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012720 * ALC662 support
12721 *
12722 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
12723 * configuration. Each pin widget can choose any input DACs and a mixer.
12724 * Each ADC is connected from a mixer of all inputs. This makes possible
12725 * 6-channel independent captures.
12726 *
12727 * In addition, an independent DAC for the multi-playback (not used in this
12728 * driver yet).
12729 */
12730#define ALC662_DIGOUT_NID 0x06
12731#define ALC662_DIGIN_NID 0x0a
12732
12733static hda_nid_t alc662_dac_nids[4] = {
12734 /* front, rear, clfe, rear_surr */
12735 0x02, 0x03, 0x04
12736};
12737
12738static hda_nid_t alc662_adc_nids[1] = {
12739 /* ADC1-2 */
12740 0x09,
12741};
Takashi Iwaie1406342008-02-11 18:32:32 +010012742
12743static hda_nid_t alc662_capsrc_nids[1] = { 0x23 };
12744
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012745/* input MUX */
12746/* FIXME: should be a matrix-type input source selection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012747static struct hda_input_mux alc662_capture_source = {
12748 .num_items = 4,
12749 .items = {
12750 { "Mic", 0x0 },
12751 { "Front Mic", 0x1 },
12752 { "Line", 0x2 },
12753 { "CD", 0x4 },
12754 },
12755};
12756
12757static struct hda_input_mux alc662_lenovo_101e_capture_source = {
12758 .num_items = 2,
12759 .items = {
12760 { "Mic", 0x1 },
12761 { "Line", 0x2 },
12762 },
12763};
Kailang Yang291702f2007-10-16 14:28:03 +020012764
12765static struct hda_input_mux alc662_eeepc_capture_source = {
12766 .num_items = 2,
12767 .items = {
12768 { "i-Mic", 0x1 },
12769 { "e-Mic", 0x0 },
12770 },
12771};
12772
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012773#define alc662_mux_enum_info alc_mux_enum_info
12774#define alc662_mux_enum_get alc_mux_enum_get
Takashi Iwaie1406342008-02-11 18:32:32 +010012775#define alc662_mux_enum_put alc882_mux_enum_put
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012776
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012777/*
12778 * 2ch mode
12779 */
12780static struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
12781 { 2, NULL }
12782};
12783
12784/*
12785 * 2ch mode
12786 */
12787static struct hda_verb alc662_3ST_ch2_init[] = {
12788 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
12789 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
12790 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
12791 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
12792 { } /* end */
12793};
12794
12795/*
12796 * 6ch mode
12797 */
12798static struct hda_verb alc662_3ST_ch6_init[] = {
12799 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12800 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12801 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
12802 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12803 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12804 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
12805 { } /* end */
12806};
12807
12808static struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
12809 { 2, alc662_3ST_ch2_init },
12810 { 6, alc662_3ST_ch6_init },
12811};
12812
12813/*
12814 * 2ch mode
12815 */
12816static struct hda_verb alc662_sixstack_ch6_init[] = {
12817 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12818 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12819 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12820 { } /* end */
12821};
12822
12823/*
12824 * 6ch mode
12825 */
12826static struct hda_verb alc662_sixstack_ch8_init[] = {
12827 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12828 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12829 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12830 { } /* end */
12831};
12832
12833static struct hda_channel_mode alc662_5stack_modes[2] = {
12834 { 2, alc662_sixstack_ch6_init },
12835 { 6, alc662_sixstack_ch8_init },
12836};
12837
12838/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
12839 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
12840 */
12841
12842static struct snd_kcontrol_new alc662_base_mixer[] = {
12843 /* output mixer control */
12844 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12845 HDA_CODEC_MUTE("Front Playback Switch", 0x02, 0x0, HDA_OUTPUT),
12846 HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12847 HDA_CODEC_MUTE("Surround Playback Switch", 0x03, 0x0, HDA_OUTPUT),
12848 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
12849 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
12850 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT),
12851 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT),
12852 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
12853
12854 /*Input mixer control */
12855 HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
12856 HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
12857 HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
12858 HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
12859 HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
12860 HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
12861 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
12862 HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012863 { } /* end */
12864};
12865
12866static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
12867 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12868 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
12869 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
12870 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
12871 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
12872 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
12873 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
12874 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12875 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12876 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12877 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
12878 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
12879 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012880 { } /* end */
12881};
12882
12883static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
12884 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12885 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
12886 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
12887 HDA_BIND_MUTE("Surround Playback Switch", 0x03, 2, HDA_INPUT),
12888 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
12889 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
12890 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT),
12891 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT),
12892 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
12893 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
12894 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
12895 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
12896 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
12897 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12898 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12899 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12900 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
12901 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
12902 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012903 { } /* end */
12904};
12905
12906static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
12907 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12908 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010012909 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
12910 HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012911 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
12912 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
12913 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
12914 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12915 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012916 { } /* end */
12917};
12918
Kailang Yang291702f2007-10-16 14:28:03 +020012919static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +010012920 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020012921
Herton Ronaldo Krzesinskib4818492008-02-23 11:34:12 +010012922 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12923 HDA_CODEC_MUTE("Line-Out Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020012924
12925 HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT),
12926 HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12927 HDA_CODEC_MUTE("e-Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12928
12929 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
12930 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12931 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
12932 { } /* end */
12933};
12934
Kailang Yang8c427222008-01-10 13:03:59 +010012935static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
Takashi Iwai31bffaa2008-02-27 16:10:44 +010012936 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12937 HDA_CODEC_MUTE("Line-Out Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010012938 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
12939 HDA_BIND_MUTE("Surround Playback Switch", 0x03, 2, HDA_INPUT),
12940 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
12941 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
12942 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT),
12943 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010012944 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010012945 HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
12946 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
12947 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
12948 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12949 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12950 { } /* end */
12951};
12952
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012953static struct snd_kcontrol_new alc662_chmode_mixer[] = {
12954 {
12955 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12956 .name = "Channel Mode",
12957 .info = alc_ch_mode_info,
12958 .get = alc_ch_mode_get,
12959 .put = alc_ch_mode_put,
12960 },
12961 { } /* end */
12962};
12963
12964static struct hda_verb alc662_init_verbs[] = {
12965 /* ADC: mute amp left and right */
12966 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12967 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12968 /* Front mixer: unmute input/output amp left and right (volume = 0) */
12969
Takashi Iwaicb53c622007-08-10 17:21:45 +020012970 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12971 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12972 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12973 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12974 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012975
Kailang Yangb60dd392007-09-20 12:50:29 +020012976 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12977 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12978 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12979 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12980 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12981 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020012982
12983 /* Front Pin: output 0 (0x0c) */
12984 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12985 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12986
12987 /* Rear Pin: output 1 (0x0d) */
12988 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12989 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12990
12991 /* CLFE Pin: output 2 (0x0e) */
12992 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12993 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12994
12995 /* Mic (rear) pin: input vref at 80% */
12996 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12997 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12998 /* Front Mic pin: input vref at 80% */
12999 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13000 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13001 /* Line In pin: input */
13002 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13003 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13004 /* Line-2 In: Headphone output (output 0 - 0x0c) */
13005 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13006 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13007 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
13008 /* CD pin widget for input */
13009 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13010
13011 /* FIXME: use matrix-type input source selection */
13012 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
13013 /* Input mixer */
13014 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13015 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13016 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13017 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Kailang Yang291702f2007-10-16 14:28:03 +020013018
13019 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13020 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13021 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13022 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013023 { }
13024};
13025
13026static struct hda_verb alc662_sue_init_verbs[] = {
13027 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
13028 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
Kailang Yang291702f2007-10-16 14:28:03 +020013029 {}
13030};
13031
13032static struct hda_verb alc662_eeepc_sue_init_verbs[] = {
13033 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13034 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
13035 {}
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013036};
13037
Kailang Yang8c427222008-01-10 13:03:59 +010013038/* Set Unsolicited Event*/
13039static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
13040 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13041 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
13042 {}
13043};
13044
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013045/*
13046 * generic initialization of ADC, input mixers and output mixers
13047 */
13048static struct hda_verb alc662_auto_init_verbs[] = {
13049 /*
13050 * Unmute ADC and set the default input to mic-in
13051 */
13052 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
13053 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13054
13055 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
13056 * mixer widget
13057 * Note: PASD motherboards uses the Line In 2 as the input for front
13058 * panel mic (mic 2)
13059 */
13060 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020013061 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13062 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13063 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
13064 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
13065 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013066
13067 /*
13068 * Set up output mixers (0x0c - 0x0f)
13069 */
13070 /* set vol=0 to output mixers */
13071 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13072 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13073 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13074
13075 /* set up input amps for analog loopback */
13076 /* Amp Indices: DAC = 0, mixer = 1 */
Kailang Yangb60dd392007-09-20 12:50:29 +020013077 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13078 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13079 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13080 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13081 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13082 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013083
13084
13085 /* FIXME: use matrix-type input source selection */
13086 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
13087 /* Input mixer */
13088 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangd1a991a2007-08-15 16:21:59 +020013089 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013090 { }
13091};
13092
13093/* capture mixer elements */
13094static struct snd_kcontrol_new alc662_capture_mixer[] = {
13095 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
13096 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
13097 {
13098 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13099 /* The multiple "Capture Source" controls confuse alsamixer
13100 * So call somewhat different..
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013101 */
13102 /* .name = "Capture Source", */
13103 .name = "Input Source",
13104 .count = 1,
Herton Ronaldo Krzesinski6e7939b2007-12-19 17:49:02 +010013105 .info = alc662_mux_enum_info,
13106 .get = alc662_mux_enum_get,
13107 .put = alc662_mux_enum_put,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013108 },
13109 { } /* end */
13110};
13111
13112static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
13113{
13114 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013115 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013116
13117 present = snd_hda_codec_read(codec, 0x14, 0,
13118 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020013119 bits = present ? HDA_AMP_MUTE : 0;
13120 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
13121 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013122}
13123
13124static void alc662_lenovo_101e_all_automute(struct hda_codec *codec)
13125{
13126 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013127 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013128
13129 present = snd_hda_codec_read(codec, 0x1b, 0,
13130 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020013131 bits = present ? HDA_AMP_MUTE : 0;
13132 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
13133 HDA_AMP_MUTE, bits);
13134 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
13135 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013136}
13137
13138static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec,
13139 unsigned int res)
13140{
13141 if ((res >> 26) == ALC880_HP_EVENT)
13142 alc662_lenovo_101e_all_automute(codec);
13143 if ((res >> 26) == ALC880_FRONT_EVENT)
13144 alc662_lenovo_101e_ispeaker_automute(codec);
13145}
13146
Kailang Yang291702f2007-10-16 14:28:03 +020013147static void alc662_eeepc_mic_automute(struct hda_codec *codec)
13148{
13149 unsigned int present;
13150
13151 present = snd_hda_codec_read(codec, 0x18, 0,
13152 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
13153 snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
13154 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
13155 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
13156 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
13157 snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
13158 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
13159 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
13160 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
13161}
13162
13163/* unsolicited event for HP jack sensing */
13164static void alc662_eeepc_unsol_event(struct hda_codec *codec,
13165 unsigned int res)
13166{
13167 if ((res >> 26) == ALC880_HP_EVENT)
13168 alc262_hippo1_automute( codec );
13169
13170 if ((res >> 26) == ALC880_MIC_EVENT)
13171 alc662_eeepc_mic_automute(codec);
13172}
13173
13174static void alc662_eeepc_inithook(struct hda_codec *codec)
13175{
13176 alc262_hippo1_automute( codec );
13177 alc662_eeepc_mic_automute(codec);
13178}
13179
Kailang Yang8c427222008-01-10 13:03:59 +010013180static void alc662_eeepc_ep20_automute(struct hda_codec *codec)
13181{
13182 unsigned int mute;
13183 unsigned int present;
13184
13185 snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
13186 present = snd_hda_codec_read(codec, 0x14, 0,
13187 AC_VERB_GET_PIN_SENSE, 0);
13188 present = (present & 0x80000000) != 0;
13189 if (present) {
13190 /* mute internal speaker */
13191 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
13192 HDA_AMP_MUTE, HDA_AMP_MUTE);
13193 } else {
13194 /* unmute internal speaker if necessary */
13195 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
13196 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
13197 HDA_AMP_MUTE, mute);
13198 }
13199}
13200
13201/* unsolicited event for HP jack sensing */
13202static void alc662_eeepc_ep20_unsol_event(struct hda_codec *codec,
13203 unsigned int res)
13204{
13205 if ((res >> 26) == ALC880_HP_EVENT)
13206 alc662_eeepc_ep20_automute(codec);
13207}
13208
13209static void alc662_eeepc_ep20_inithook(struct hda_codec *codec)
13210{
13211 alc662_eeepc_ep20_automute(codec);
13212}
13213
Takashi Iwaicb53c622007-08-10 17:21:45 +020013214#ifdef CONFIG_SND_HDA_POWER_SAVE
13215#define alc662_loopbacks alc880_loopbacks
13216#endif
13217
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013218
13219/* pcm configuration: identiacal with ALC880 */
13220#define alc662_pcm_analog_playback alc880_pcm_analog_playback
13221#define alc662_pcm_analog_capture alc880_pcm_analog_capture
13222#define alc662_pcm_digital_playback alc880_pcm_digital_playback
13223#define alc662_pcm_digital_capture alc880_pcm_digital_capture
13224
13225/*
13226 * configuration and preset
13227 */
13228static const char *alc662_models[ALC662_MODEL_LAST] = {
13229 [ALC662_3ST_2ch_DIG] = "3stack-dig",
13230 [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
13231 [ALC662_3ST_6ch] = "3stack-6ch",
13232 [ALC662_5ST_DIG] = "6stack-dig",
13233 [ALC662_LENOVO_101E] = "lenovo-101e",
Takashi Iwaib995d762007-10-17 10:41:06 +020013234 [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
Kailang Yang8c427222008-01-10 13:03:59 +010013235 [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013236 [ALC662_AUTO] = "auto",
13237};
13238
13239static struct snd_pci_quirk alc662_cfg_tbl[] = {
Kailang Yang291702f2007-10-16 14:28:03 +020013240 SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
Kailang Yang8c427222008-01-10 13:03:59 +010013241 SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013242 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013243 {}
13244};
13245
13246static struct alc_config_preset alc662_presets[] = {
13247 [ALC662_3ST_2ch_DIG] = {
Kailang Yang291702f2007-10-16 14:28:03 +020013248 .mixers = { alc662_3ST_2ch_mixer, alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013249 .init_verbs = { alc662_init_verbs },
13250 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13251 .dac_nids = alc662_dac_nids,
13252 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013253 .dig_in_nid = ALC662_DIGIN_NID,
13254 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
13255 .channel_mode = alc662_3ST_2ch_modes,
13256 .input_mux = &alc662_capture_source,
13257 },
13258 [ALC662_3ST_6ch_DIG] = {
Kailang Yang291702f2007-10-16 14:28:03 +020013259 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer,
13260 alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013261 .init_verbs = { alc662_init_verbs },
13262 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13263 .dac_nids = alc662_dac_nids,
13264 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013265 .dig_in_nid = ALC662_DIGIN_NID,
13266 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
13267 .channel_mode = alc662_3ST_6ch_modes,
13268 .need_dac_fix = 1,
13269 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013270 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013271 [ALC662_3ST_6ch] = {
Kailang Yang291702f2007-10-16 14:28:03 +020013272 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer,
13273 alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013274 .init_verbs = { alc662_init_verbs },
13275 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13276 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013277 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
13278 .channel_mode = alc662_3ST_6ch_modes,
13279 .need_dac_fix = 1,
13280 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013281 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013282 [ALC662_5ST_DIG] = {
Kailang Yang291702f2007-10-16 14:28:03 +020013283 .mixers = { alc662_base_mixer, alc662_chmode_mixer,
13284 alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013285 .init_verbs = { alc662_init_verbs },
13286 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13287 .dac_nids = alc662_dac_nids,
13288 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013289 .dig_in_nid = ALC662_DIGIN_NID,
13290 .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
13291 .channel_mode = alc662_5stack_modes,
13292 .input_mux = &alc662_capture_source,
13293 },
13294 [ALC662_LENOVO_101E] = {
Kailang Yang291702f2007-10-16 14:28:03 +020013295 .mixers = { alc662_lenovo_101e_mixer, alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013296 .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
13297 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13298 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013299 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
13300 .channel_mode = alc662_3ST_2ch_modes,
13301 .input_mux = &alc662_lenovo_101e_capture_source,
13302 .unsol_event = alc662_lenovo_101e_unsol_event,
13303 .init_hook = alc662_lenovo_101e_all_automute,
13304 },
Kailang Yang291702f2007-10-16 14:28:03 +020013305 [ALC662_ASUS_EEEPC_P701] = {
13306 .mixers = { alc662_eeepc_p701_mixer, alc662_capture_mixer },
13307 .init_verbs = { alc662_init_verbs,
13308 alc662_eeepc_sue_init_verbs },
13309 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13310 .dac_nids = alc662_dac_nids,
Kailang Yang291702f2007-10-16 14:28:03 +020013311 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
13312 .channel_mode = alc662_3ST_2ch_modes,
13313 .input_mux = &alc662_eeepc_capture_source,
13314 .unsol_event = alc662_eeepc_unsol_event,
13315 .init_hook = alc662_eeepc_inithook,
13316 },
Kailang Yang8c427222008-01-10 13:03:59 +010013317 [ALC662_ASUS_EEEPC_EP20] = {
13318 .mixers = { alc662_eeepc_ep20_mixer, alc662_capture_mixer,
13319 alc662_chmode_mixer },
13320 .init_verbs = { alc662_init_verbs,
13321 alc662_eeepc_ep20_sue_init_verbs },
13322 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
13323 .dac_nids = alc662_dac_nids,
Kailang Yang8c427222008-01-10 13:03:59 +010013324 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
13325 .channel_mode = alc662_3ST_6ch_modes,
13326 .input_mux = &alc662_lenovo_101e_capture_source,
13327 .unsol_event = alc662_eeepc_ep20_unsol_event,
13328 .init_hook = alc662_eeepc_ep20_inithook,
13329 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013330
13331};
13332
13333
13334/*
13335 * BIOS auto configuration
13336 */
13337
13338/* add playback controls from the parsed DAC table */
13339static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec,
13340 const struct auto_pin_cfg *cfg)
13341{
13342 char name[32];
13343 static const char *chname[4] = {
13344 "Front", "Surround", NULL /*CLFE*/, "Side"
13345 };
13346 hda_nid_t nid;
13347 int i, err;
13348
13349 for (i = 0; i < cfg->line_outs; i++) {
13350 if (!spec->multiout.dac_nids[i])
13351 continue;
Kailang Yangb60dd392007-09-20 12:50:29 +020013352 nid = alc880_idx_to_dac(i);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013353 if (i == 2) {
13354 /* Center/LFE */
13355 err = add_control(spec, ALC_CTL_WIDGET_VOL,
13356 "Center Playback Volume",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013357 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
13358 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013359 if (err < 0)
13360 return err;
13361 err = add_control(spec, ALC_CTL_WIDGET_VOL,
13362 "LFE Playback Volume",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013363 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
13364 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013365 if (err < 0)
13366 return err;
13367 err = add_control(spec, ALC_CTL_BIND_MUTE,
13368 "Center Playback Switch",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013369 HDA_COMPOSE_AMP_VAL(nid, 1, 2,
13370 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013371 if (err < 0)
13372 return err;
13373 err = add_control(spec, ALC_CTL_BIND_MUTE,
13374 "LFE Playback Switch",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013375 HDA_COMPOSE_AMP_VAL(nid, 2, 2,
13376 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013377 if (err < 0)
13378 return err;
13379 } else {
13380 sprintf(name, "%s Playback Volume", chname[i]);
13381 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013382 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
13383 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013384 if (err < 0)
13385 return err;
13386 sprintf(name, "%s Playback Switch", chname[i]);
13387 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013388 HDA_COMPOSE_AMP_VAL(nid, 3, 2,
13389 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013390 if (err < 0)
13391 return err;
13392 }
13393 }
13394 return 0;
13395}
13396
13397/* add playback controls for speaker and HP outputs */
13398static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
13399 const char *pfx)
13400{
13401 hda_nid_t nid;
13402 int err;
13403 char name[32];
13404
13405 if (!pin)
13406 return 0;
13407
13408 if (alc880_is_fixed_pin(pin)) {
13409 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
13410 /* printk("DAC nid=%x\n",nid); */
13411 /* specify the DAC as the extra output */
13412 if (!spec->multiout.hp_nid)
13413 spec->multiout.hp_nid = nid;
13414 else
13415 spec->multiout.extra_out_nid[0] = nid;
13416 /* control HP volume/switch on the output mixer amp */
13417 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
13418 sprintf(name, "%s Playback Volume", pfx);
13419 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
13420 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
13421 if (err < 0)
13422 return err;
13423 sprintf(name, "%s Playback Switch", pfx);
13424 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
13425 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
13426 if (err < 0)
13427 return err;
13428 } else if (alc880_is_multi_pin(pin)) {
13429 /* set manual connection */
13430 /* we have only a switch on HP-out PIN */
13431 sprintf(name, "%s Playback Switch", pfx);
13432 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
13433 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
13434 if (err < 0)
13435 return err;
13436 }
13437 return 0;
13438}
13439
13440/* create playback/capture controls for input pins */
13441static int alc662_auto_create_analog_input_ctls(struct alc_spec *spec,
13442 const struct auto_pin_cfg *cfg)
13443{
13444 struct hda_input_mux *imux = &spec->private_imux;
13445 int i, err, idx;
13446
13447 for (i = 0; i < AUTO_PIN_LAST; i++) {
13448 if (alc880_is_input_pin(cfg->input_pins[i])) {
13449 idx = alc880_input_pin_idx(cfg->input_pins[i]);
13450 err = new_analog_input(spec, cfg->input_pins[i],
13451 auto_pin_cfg_labels[i],
13452 idx, 0x0b);
13453 if (err < 0)
13454 return err;
13455 imux->items[imux->num_items].label =
13456 auto_pin_cfg_labels[i];
13457 imux->items[imux->num_items].index =
13458 alc880_input_pin_idx(cfg->input_pins[i]);
13459 imux->num_items++;
13460 }
13461 }
13462 return 0;
13463}
13464
13465static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
13466 hda_nid_t nid, int pin_type,
13467 int dac_idx)
13468{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013469 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013470 /* need the manual connection? */
13471 if (alc880_is_multi_pin(nid)) {
13472 struct alc_spec *spec = codec->spec;
13473 int idx = alc880_multi_pin_idx(nid);
13474 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
13475 AC_VERB_SET_CONNECT_SEL,
13476 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
13477 }
13478}
13479
13480static void alc662_auto_init_multi_out(struct hda_codec *codec)
13481{
13482 struct alc_spec *spec = codec->spec;
13483 int i;
13484
Kailang Yang8c427222008-01-10 13:03:59 +010013485 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013486 for (i = 0; i <= HDA_SIDE; i++) {
13487 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020013488 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013489 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020013490 alc662_auto_set_output_and_unmute(codec, nid, pin_type,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013491 i);
13492 }
13493}
13494
13495static void alc662_auto_init_hp_out(struct hda_codec *codec)
13496{
13497 struct alc_spec *spec = codec->spec;
13498 hda_nid_t pin;
13499
13500 pin = spec->autocfg.hp_pins[0];
13501 if (pin) /* connect to front */
13502 /* use dac 0 */
13503 alc662_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013504 pin = spec->autocfg.speaker_pins[0];
13505 if (pin)
13506 alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013507}
13508
13509#define alc662_is_input_pin(nid) alc880_is_input_pin(nid)
13510#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID
13511
13512static void alc662_auto_init_analog_input(struct hda_codec *codec)
13513{
13514 struct alc_spec *spec = codec->spec;
13515 int i;
13516
13517 for (i = 0; i < AUTO_PIN_LAST; i++) {
13518 hda_nid_t nid = spec->autocfg.input_pins[i];
13519 if (alc662_is_input_pin(nid)) {
13520 snd_hda_codec_write(codec, nid, 0,
13521 AC_VERB_SET_PIN_WIDGET_CONTROL,
13522 (i <= AUTO_PIN_FRONT_MIC ?
13523 PIN_VREF80 : PIN_IN));
13524 if (nid != ALC662_PIN_CD_NID)
13525 snd_hda_codec_write(codec, nid, 0,
13526 AC_VERB_SET_AMP_GAIN_MUTE,
13527 AMP_OUT_MUTE);
13528 }
13529 }
13530}
13531
13532static int alc662_parse_auto_config(struct hda_codec *codec)
13533{
13534 struct alc_spec *spec = codec->spec;
13535 int err;
13536 static hda_nid_t alc662_ignore[] = { 0x1d, 0 };
13537
13538 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
13539 alc662_ignore);
13540 if (err < 0)
13541 return err;
13542 if (!spec->autocfg.line_outs)
13543 return 0; /* can't find valid BIOS pin config */
13544
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013545 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
13546 if (err < 0)
13547 return err;
13548 err = alc662_auto_create_multi_out_ctls(spec, &spec->autocfg);
13549 if (err < 0)
13550 return err;
13551 err = alc662_auto_create_extra_out(spec,
13552 spec->autocfg.speaker_pins[0],
13553 "Speaker");
13554 if (err < 0)
13555 return err;
13556 err = alc662_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
13557 "Headphone");
13558 if (err < 0)
13559 return err;
13560 err = alc662_auto_create_analog_input_ctls(spec, &spec->autocfg);
13561 if (err < 0)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013562 return err;
13563
13564 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
13565
13566 if (spec->autocfg.dig_out_pin)
13567 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
13568
13569 if (spec->kctl_alloc)
13570 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
13571
13572 spec->num_mux_defs = 1;
13573 spec->input_mux = &spec->private_imux;
13574
Takashi Iwai8c872862007-06-19 12:11:16 +020013575 spec->init_verbs[spec->num_init_verbs++] = alc662_auto_init_verbs;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013576 spec->mixers[spec->num_mixers] = alc662_capture_mixer;
13577 spec->num_mixers++;
Takashi Iwai8c872862007-06-19 12:11:16 +020013578 return 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013579}
13580
13581/* additional initialization for auto-configuration model */
13582static void alc662_auto_init(struct hda_codec *codec)
13583{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013584 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013585 alc662_auto_init_multi_out(codec);
13586 alc662_auto_init_hp_out(codec);
13587 alc662_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013588 if (spec->unsol_event)
13589 alc_sku_automute(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013590}
13591
13592static int patch_alc662(struct hda_codec *codec)
13593{
13594 struct alc_spec *spec;
13595 int err, board_config;
13596
13597 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
13598 if (!spec)
13599 return -ENOMEM;
13600
13601 codec->spec = spec;
13602
13603 board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
13604 alc662_models,
13605 alc662_cfg_tbl);
13606 if (board_config < 0) {
13607 printk(KERN_INFO "hda_codec: Unknown model for ALC662, "
13608 "trying auto-probe from BIOS...\n");
13609 board_config = ALC662_AUTO;
13610 }
13611
13612 if (board_config == ALC662_AUTO) {
13613 /* automatic parse from the BIOS config */
13614 err = alc662_parse_auto_config(codec);
13615 if (err < 0) {
13616 alc_free(codec);
13617 return err;
Takashi Iwai8c872862007-06-19 12:11:16 +020013618 } else if (!err) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013619 printk(KERN_INFO
13620 "hda_codec: Cannot set up configuration "
13621 "from BIOS. Using base mode...\n");
13622 board_config = ALC662_3ST_2ch_DIG;
13623 }
13624 }
13625
13626 if (board_config != ALC662_AUTO)
13627 setup_preset(spec, &alc662_presets[board_config]);
13628
13629 spec->stream_name_analog = "ALC662 Analog";
13630 spec->stream_analog_playback = &alc662_pcm_analog_playback;
13631 spec->stream_analog_capture = &alc662_pcm_analog_capture;
13632
13633 spec->stream_name_digital = "ALC662 Digital";
13634 spec->stream_digital_playback = &alc662_pcm_digital_playback;
13635 spec->stream_digital_capture = &alc662_pcm_digital_capture;
13636
Takashi Iwaie1406342008-02-11 18:32:32 +010013637 spec->adc_nids = alc662_adc_nids;
13638 spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
13639 spec->capsrc_nids = alc662_capsrc_nids;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013640
Takashi Iwai2134ea42008-01-10 16:53:55 +010013641 spec->vmaster_nid = 0x02;
13642
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013643 codec->patch_ops = alc_patch_ops;
13644 if (board_config == ALC662_AUTO)
13645 spec->init_hook = alc662_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020013646#ifdef CONFIG_SND_HDA_POWER_SAVE
13647 if (!spec->loopback.amplist)
13648 spec->loopback.amplist = alc662_loopbacks;
13649#endif
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013650
13651 return 0;
13652}
13653
13654/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070013655 * patch entries
13656 */
13657struct hda_codec_preset snd_hda_preset_realtek[] = {
13658 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +010013659 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +010013660 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +020013661 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +010013662 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013663 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013664 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013665 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
13666 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
13667 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013668 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
13669 .patch = patch_alc883 },
13670 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
13671 .patch = patch_alc662 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013672 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070013673 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013674 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 },
Kailang Yangdf694da2005-12-05 19:42:22 +010013675 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013676 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 },
Kailang Yangf6a92242007-12-13 16:52:54 +010013677 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc883 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070013678 {} /* terminator */
13679};